From 8921b947fb373b984994b6859b5d80823c5746f3 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Mon, 3 Oct 2022 10:48:27 +0800 Subject: [PATCH 01/15] WIP: dev --- .vscode/launch.json | 11 + packages/runtime/package.json | 4 +- packages/schema/package.json | 3 +- packages/schema/src/cli/index.ts | 18 +- packages/schema/src/generator/prisma/index.ts | 287 ++++++++++ .../src/generator/prisma/prisma-builder.ts | 280 ++++++++++ packages/schema/src/generator/types.ts | 16 + .../src/language-server/generated/ast.ts | 144 ++++- .../src/language-server/generated/grammar.ts | 491 ++++++++++++++++-- .../schema/src/language-server/stdlib.zmodel | 3 +- .../src/language-server/zmodel-linker.ts | 19 +- .../schema/src/language-server/zmodel.langium | 47 +- packages/schema/src/utils/indent-string.ts | 41 ++ .../schema/syntaxes/zmodel.tmLanguage.json | 2 +- packages/schema/tests/parser.test.ts | 153 +++--- packages/schema/tests/todo-sample.test.ts | 13 +- packages/schema/tsconfig.json | 3 +- pnpm-lock.yaml | 96 +++- 18 files changed, 1477 insertions(+), 154 deletions(-) create mode 100644 packages/schema/src/generator/prisma/index.ts create mode 100644 packages/schema/src/generator/prisma/prisma-builder.ts create mode 100644 packages/schema/src/generator/types.ts create mode 100644 packages/schema/src/utils/indent-string.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 97c567d0e..4ccd03843 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,6 +5,17 @@ { "version": "0.2.0", "configurations": [ + { + "name": "Launch CLI", + "program": "${workspaceFolder}/packages/schema/bin/cli", + "args": [ + "generate", + "${workspaceFolder}/samples/todo/schema.zmodel" + ], + "request": "launch", + "skipFiles": ["/**"], + "type": "node" + }, { "name": "Attach", "port": 9229, diff --git a/packages/runtime/package.json b/packages/runtime/package.json index faffea17c..95cf323dc 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { - "name": "runtime", - "version": "0.0.3", + "name": "@zenstackhq/runtime", + "version": "0.1.0", "description": "", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/packages/schema/package.json b/packages/schema/package.json index 7cb259f6c..50a26fb6f 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -2,7 +2,7 @@ "name": "@zenstackhq/schema", "displayName": "ZenStack Data Modeling Schema Language", "description": "Please enter a brief description here", - "version": "0.0.1", + "version": "0.1.0", "engines": { "vscode": "^1.56.0" }, @@ -63,6 +63,7 @@ "commander": "^8.0.0", "langium": "^0.4.0", "uuid": "^9.0.0", + "vscode-jsonrpc": "^8.0.2", "vscode-languageclient": "^7.0.0", "vscode-languageserver": "^7.0.0", "vscode-uri": "^3.0.2" diff --git a/packages/schema/src/cli/index.ts b/packages/schema/src/cli/index.ts index 8088d41dc..8610a981d 100644 --- a/packages/schema/src/cli/index.ts +++ b/packages/schema/src/cli/index.ts @@ -5,6 +5,8 @@ import { ZModelLanguageMetaData } from '../language-server/generated/module'; import { createZModelServices } from '../language-server/zmodel-module'; import { extractAstNode } from './cli-util'; import { generateJavaScript } from './generator'; +import PrismaGenerator from '../generator/prisma'; +import { Context } from '../generator/types'; export const generateAction = async ( fileName: string, @@ -12,6 +14,17 @@ export const generateAction = async ( ): Promise => { const services = createZModelServices().ZModel; const model = await extractAstNode(fileName, services); + + const generators = [new PrismaGenerator()]; + const context: Context = { + schema: model, + outDir: opts.destination, + }; + + for (const generator of generators) { + await generator.generate(context); + } + const generatedFilePath = generateJavaScript( model, fileName, @@ -25,7 +38,7 @@ export const generateAction = async ( }; export type GenerateOptions = { - destination?: string; + destination: string; }; export default function (): void { @@ -44,7 +57,8 @@ export default function (): void { ) .option( '-d, --destination ', - 'destination directory of generating' + 'destination directory of generating', + '.zenstack' ) .description( 'generates JavaScript code that prints "Hello, {name}!" for each greeting in a source file' diff --git a/packages/schema/src/generator/prisma/index.ts b/packages/schema/src/generator/prisma/index.ts new file mode 100644 index 000000000..79dcfd197 --- /dev/null +++ b/packages/schema/src/generator/prisma/index.ts @@ -0,0 +1,287 @@ +import { writeFile } from 'fs/promises'; +import { AstNode } from 'langium'; +import path from 'path'; +import colors from 'colors'; +import { + AttributeArg, + DataModel, + DataModelAttribute, + DataModelField, + DataModelFieldAttribute, + DataSource, + Enum, + Expression, + InvocationExpr, + isArrayExpr, + isInvocationExpr, + isLiteralExpr, + isReferenceExpr, + LiteralExpr, +} from '../../language-server/generated/ast'; +import { Context, Generator, GeneratorError } from '../types'; +import { + AttributeArg as PrismaAttributeArg, + AttributeArgValue as PrismaAttributeArgValue, + DataSourceUrl as PrismaDataSourceUrl, + FieldAttribute as PrismaFieldAttribute, + ModelAttribute as PrismaModelAttribute, + Model as PrismaDataModel, + FieldReference as PrismaFieldReference, + FieldReferenceArg as PrismaFieldReferenceArg, + FunctionCall as PrismaFunctionCall, + FunctionCallArg as PrismaFunctionCallArg, + PrismaModel, +} from './prisma-builder'; + +const supportedProviders = ['postgresql', 'mysql', 'sqlite', 'sqlserver']; + +export default class PrismaGenerator implements Generator { + async generate(context: Context) { + const { schema } = context; + const prisma = new PrismaModel(); + + for (const decl of schema.declarations) { + switch (decl.$type) { + case DataSource: + this.generateDataSource( + context, + prisma, + decl as DataSource + ); + break; + + case Enum: + this.generateEnum(context, prisma, decl as Enum); + break; + + case DataModel: + this.generateModel(context, prisma, decl as DataModel); + break; + } + } + + this.generateGenerator(context, prisma); + + await writeFile( + path.join(context.outDir, 'schema.prisma'), + prisma.toString() + ); + + console.log(colors.green('Prisma schema generated successfully')); + } + + private isStringLiteral(node: AstNode): node is LiteralExpr { + return isLiteralExpr(node) && typeof node.value === 'string'; + } + + private generateDataSource( + context: Context, + prisma: PrismaModel, + dataSource: DataSource + ) { + let provider: string | undefined = undefined; + let url: PrismaDataSourceUrl | undefined = undefined; + let shadowDatabaseUrl: PrismaDataSourceUrl | undefined = undefined; + + for (const f of dataSource.fields) { + switch (f.name) { + case 'provider': { + if (this.isStringLiteral(f.value)) { + provider = f.value.value as string; + } else { + throw new GeneratorError( + 'Datasource provider must be set to a string' + ); + } + if (!supportedProviders.includes(provider)) { + throw new GeneratorError( + `Provider ${provider} is not supported. Supported providers: ${supportedProviders.join( + ', ' + )}` + ); + } + break; + } + + case 'url': { + const r = this.extractDataSourceUrl(f.value); + if (!r) { + throw new GeneratorError( + 'Invalid value for datasource url' + ); + } + url = r; + break; + } + + case 'shadowDatabaseUrl': { + const r = this.extractDataSourceUrl(f.value); + if (!r) { + throw new GeneratorError( + 'Invalid value for datasource url' + ); + } + shadowDatabaseUrl = r; + break; + } + } + } + + if (!provider) { + throw new GeneratorError('Datasource is missing "provider" field'); + } + if (!url) { + throw new GeneratorError('Datasource is missing "url" field'); + } + + prisma.addDataSource(dataSource.name, provider, url, shadowDatabaseUrl); + } + + private extractDataSourceUrl(fieldValue: LiteralExpr | InvocationExpr) { + if (this.isStringLiteral(fieldValue)) { + return new PrismaDataSourceUrl(fieldValue.value as string, false); + } else if ( + isInvocationExpr(fieldValue) && + fieldValue.function.ref?.name === 'env' && + fieldValue.args.length === 1 && + this.isStringLiteral(fieldValue.args[0]) + ) { + return new PrismaDataSourceUrl( + fieldValue.args[0].value as string, + true + ); + } else { + return null; + } + } + + private generateGenerator(context: Context, prisma: PrismaModel) { + prisma.addGenerator( + 'client', + 'prisma-client-js', + path.join(context.outDir, '.prisma') + ); + } + + private generateModel( + context: Context, + prisma: PrismaModel, + decl: DataModel + ) { + const model = prisma.addModel(decl.name); + for (const field of decl.fields) { + this.generateModelField(model, field); + } + + for (const attr of decl.attributes) { + this.generateModelAttribute(model, attr); + } + } + + private generateModelField(model: PrismaDataModel, field: DataModelField) { + const type = { + type: (field.type.type || field.type.reference?.ref?.name)!, + array: field.type.array, + optional: field.type.optional, + }; + + const attributes = field.attributes.map((attr) => + this.makeFieldAttribute(attr) + ); + model.addField(field.name, type, attributes); + } + + private makeFieldAttribute(attr: DataModelFieldAttribute) { + return new PrismaFieldAttribute( + attr.decl.ref?.name!, + attr.args.map((arg) => this.makeAttributeArg(arg)) + ); + } + + makeAttributeArg(arg: AttributeArg): PrismaAttributeArg { + return new PrismaAttributeArg( + arg.name, + this.makeAttributeArgValue(arg.value) + ); + } + + makeAttributeArgValue(node: Expression): PrismaAttributeArgValue { + if (isLiteralExpr(node)) { + switch (typeof node.value) { + case 'string': + return new PrismaAttributeArgValue('String', node.value); + case 'number': + return new PrismaAttributeArgValue('Number', node.value); + case 'boolean': + return new PrismaAttributeArgValue('Boolean', node.value); + default: + throw new GeneratorError( + `Unexpected literal type: ${typeof node.value}` + ); + } + } else if (isArrayExpr(node)) { + return new PrismaAttributeArgValue( + 'Array', + new Array( + ...node.items.map((item) => + this.makeAttributeArgValue(item) + ) + ) + ); + } else if (isReferenceExpr(node)) { + return new PrismaAttributeArgValue( + 'FieldReference', + new PrismaFieldReference( + node.target.ref?.name!, + node.args.map( + (arg) => + new PrismaFieldReferenceArg(arg.name, arg.value) + ) + ) + ); + } else if (isInvocationExpr(node)) { + // invocation + return new PrismaAttributeArgValue( + 'FunctionCall', + this.makeFunctionCall(node) + ); + } else { + throw new GeneratorError( + `Unsupported attribute argument expression type: ${node.$type}` + ); + } + } + + makeFunctionCall(node: InvocationExpr): PrismaFunctionCall { + return new PrismaFunctionCall( + node.function.ref?.name!, + node.args.map((arg) => { + if (!isLiteralExpr(arg.value)) { + throw new GeneratorError( + 'Function call argument must be literal' + ); + } + return new PrismaFunctionCallArg(arg.name, arg.value.value); + }) + ); + } + + private generateModelAttribute( + model: PrismaDataModel, + attr: DataModelAttribute + ) { + model.attributes.push( + new PrismaModelAttribute( + attr.decl.ref?.name!, + attr.args.map((arg) => this.makeAttributeArg(arg)) + ) + ); + } + + private generateEnum(context: Context, prisma: PrismaModel, decl: Enum) { + prisma.addEnum( + decl.name, + decl.fields.map((f) => f.name) + ); + } +} diff --git a/packages/schema/src/generator/prisma/prisma-builder.ts b/packages/schema/src/generator/prisma/prisma-builder.ts new file mode 100644 index 000000000..5c491334c --- /dev/null +++ b/packages/schema/src/generator/prisma/prisma-builder.ts @@ -0,0 +1,280 @@ +import indentString from 'utils/indent-string'; + +export class PrismaModel { + private datasources: DataSource[] = []; + private generators: Generator[] = []; + private models: Model[] = []; + private enums: Enum[] = []; + + addDataSource( + name: string, + provider: string, + url: DataSourceUrl, + shadowDatabaseUrl?: DataSourceUrl + ) { + const ds = new DataSource(name, provider, url, shadowDatabaseUrl); + this.datasources.push(ds); + return ds; + } + + addGenerator(name: string, provider: string, output: string) { + const generator = new Generator(name, provider, output); + this.generators.push(generator); + return generator; + } + + addModel(name: string) { + const model = new Model(name); + this.models.push(model); + return model; + } + + addEnum(name: string, fields: string[]) { + const e = new Enum(name, fields); + this.enums.push(e); + return e; + } + + toString() { + return [ + ...this.datasources, + ...this.generators, + ...this.enums, + ...this.models, + ] + .map((d) => d.toString()) + .join('\n\n'); + } +} + +export class DataSource { + constructor( + public name: string, + public provider: string, + public url: DataSourceUrl, + public shadowDatabaseUrl?: DataSourceUrl + ) {} + + toString() { + return `datasource ${this.name} {\n` + + indentString(`provider="${this.provider}"\n`) + + indentString(`url=${this.url}\n`) + + this.shadowDatabaseUrl + ? indentString(`shadowDatabaseurl=${this.shadowDatabaseUrl}\n`) + : '' + `}`; + } +} + +export class DataSourceUrl { + constructor(public value: string, public isEnv: boolean) {} + + toString() { + return this.isEnv ? `env("${this.value}")` : `"${this.value}"`; + } +} + +export class Generator { + constructor( + public name: string, + public provider: string, + public output: string + ) {} + + toString() { + return ( + `generator ${this.name} {` + + indentString(`provider = "${this.provider}"\n`) + + indentString(`output = "${this.output}"\n`) + + `}` + ); + } +} + +export class Model { + public fields: ModelField[] = []; + public attributes: ModelAttribute[] = []; + constructor(public name: string) {} + + addField( + name: string, + type: ModelFieldType, + attributes: ModelAttribute[] = [] + ) { + const field = new ModelField(name, type, attributes); + this.fields.push(field); + return field; + } + + toString() { + return ( + `model ${this.name} {` + + indentString( + [...this.fields, ...this.attributes] + .map((d) => d.toString()) + .join('\n') + ) + + `}` + ); + } +} + +export type ScalarTypes = + | 'String' + | 'Boolean' + | 'Int' + | 'BigInt' + | 'Float' + | 'Decimal' + | 'DateTime' + | 'Json' + | 'Bytes' + | 'Unsupported'; + +export type ModelFieldType = { + type: ScalarTypes | string; + array?: boolean; + optional?: boolean; +}; + +export class ModelField { + constructor( + public name: string, + public type: ModelFieldType, + public attributes: FieldAttribute[] = [] + ) {} + + addAttribute(name: string, args: AttributeArg[] = []) { + const attr = new FieldAttribute(name, args); + this.attributes.push(attr); + return attr; + } + + toString() { + return ( + `${this.name} ${this.type}` + + (this.attributes.length > 0 + ? ' ' + this.attributes.map((a) => a.toString()).join(' ') + : '') + ); + } +} + +export class FieldAttribute { + constructor(public name: string, public args: AttributeArg[] = []) {} + + toString() { + return ( + `@${this.name}(` + + this.args.map((a) => a.toString()).join(', ') + + `)` + ); + } +} + +export class ModelAttribute { + constructor(public name: string, public args: AttributeArg[] = []) {} + + toString() { + return ( + `@@${this.name}(` + + this.args.map((a) => a.toString()).join(', ') + + `)` + ); + } +} + +export class AttributeArg { + constructor( + public name: string | undefined, + public value: AttributeArgValue + ) {} + + toString() { + return this.name + ? `${this.name}: ${this.value}` + : this.value.toString(); + } +} + +export class AttributeArgValue { + constructor( + public type: + | 'String' + | 'FieldReference' + | 'Number' + | 'Boolean' + | 'Array' + | 'FunctionCall', + public value: + | string + | number + | boolean + | FieldReference + | FunctionCall + | AttributeArgValue[] + ) {} + + toString(): string { + switch (this.type) { + case 'String': + return `"${this.value}"`; + case 'Number': + case 'FieldReference': + case 'FunctionCall': + return this.value.toString(); + case 'Boolean': + return this.value ? 'true' : 'false'; + case 'Array': + return ( + '[' + + (this.value as AttributeArgValue[]) + .map((v) => v.toString()) + .join(', ') + + ']' + ); + default: + throw new Error(`Unknown attribute value type ${this.type}`); + } + } +} + +export class FieldReference { + constructor(public field: string, public args: FieldReferenceArg[] = []) {} +} + +export class FieldReferenceArg { + constructor(public name: 'sort', value: 'Asc' | 'Desc') {} +} + +export class FunctionCall { + constructor(public func: string, public args: FunctionCallArg[]) {} + + toString() { + return ( + `${this.func}` + + '(' + + this.args.map((a) => a.toString()).join(', ') + + ')' + ); + } +} + +export class FunctionCallArg { + constructor(public name: string | undefined, public value: any) {} + + toString() { + return this.name ? `${this.name}: ${this.value}` : this.value; + } +} + +export class Enum { + constructor(public name: string, public fields: EnumField[]) {} + + toString() { + return ( + `enum ${this.name} {\n` + indentString(this.fields.join('\n')) + '}' + ); + } +} + +type EnumField = String; diff --git a/packages/schema/src/generator/types.ts b/packages/schema/src/generator/types.ts new file mode 100644 index 000000000..0f63d3e35 --- /dev/null +++ b/packages/schema/src/generator/types.ts @@ -0,0 +1,16 @@ +import { Model } from '../language-server/generated/ast'; + +export interface Context { + schema: Model; + outDir: string; +} + +export interface Generator { + generate(context: Context): Promise; +} + +export class GeneratorError extends Error { + constructor(message: string) { + super(message); + } +} diff --git a/packages/schema/src/language-server/generated/ast.ts b/packages/schema/src/language-server/generated/ast.ts index 7fc948c51..dea8475f8 100644 --- a/packages/schema/src/language-server/generated/ast.ts +++ b/packages/schema/src/language-server/generated/ast.ts @@ -15,7 +15,7 @@ export function isAbstractDeclaration(item: unknown): item is AbstractDeclaratio return reflection.isInstance(item, AbstractDeclaration); } -export type Expression = ArrayExpr | BinaryExpr | InvocationExpr | LiteralExpr | MemberAccessExpr | ReferenceExpr | ThisExpr | UnaryExpr; +export type Expression = ArrayExpr | BinaryExpr | CascadeExpr | InvocationExpr | LiteralExpr | MemberAccessExpr | NullExpr | ReferenceExpr | ThisExpr | UnaryExpr; export const Expression = 'Expression'; @@ -39,8 +39,20 @@ export function isTypeDeclaration(item: unknown): item is TypeDeclaration { return reflection.isInstance(item, TypeDeclaration); } +export interface Argument extends AstNode { + readonly $container: InvocationExpr; + name?: string + value: Expression +} + +export const Argument = 'Argument'; + +export function isArgument(item: unknown): item is Argument { + return reflection.isInstance(item, Argument); +} + export interface ArrayExpr extends AstNode { - readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; items: Array } @@ -53,7 +65,7 @@ export function isArrayExpr(item: unknown): item is ArrayExpr { export interface Attribute extends AstNode { readonly $container: Model; name: string - params: Array + params: Array } export const Attribute = 'Attribute'; @@ -62,8 +74,46 @@ export function isAttribute(item: unknown): item is Attribute { return reflection.isInstance(item, Attribute); } +export interface AttributeArg extends AstNode { + readonly $container: DataModelAttribute | DataModelFieldAttribute; + name?: string + value: Expression +} + +export const AttributeArg = 'AttributeArg'; + +export function isAttributeArg(item: unknown): item is AttributeArg { + return reflection.isInstance(item, AttributeArg); +} + +export interface AttributeParam extends AstNode { + readonly $container: Attribute; + name: string + positional: boolean + type: AttributeParamType +} + +export const AttributeParam = 'AttributeParam'; + +export function isAttributeParam(item: unknown): item is AttributeParam { + return reflection.isInstance(item, AttributeParam); +} + +export interface AttributeParamType extends AstNode { + readonly $container: AttributeParam; + array: boolean + optional: boolean + type: 'Boolean' | 'DateTime' | 'FieldReference' | 'Int' | 'JSON' | 'String' +} + +export const AttributeParamType = 'AttributeParamType'; + +export function isAttributeParamType(item: unknown): item is AttributeParamType { + return reflection.isInstance(item, AttributeParamType); +} + export interface BinaryExpr extends AstNode { - readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; left: Expression operator: '!' | '!=' | '&&' | '*' | '+' | '-' | '/' | '<' | '<=' | '==' | '>' | '>=' | '?' | '||' right: Expression @@ -75,6 +125,17 @@ export function isBinaryExpr(item: unknown): item is BinaryExpr { return reflection.isInstance(item, BinaryExpr); } +export interface CascadeExpr extends AstNode { + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; + value: string +} + +export const CascadeExpr = 'CascadeExpr'; + +export function isCascadeExpr(item: unknown): item is CascadeExpr { + return reflection.isInstance(item, CascadeExpr); +} + export interface DataModel extends AstNode { readonly $container: Model; attributes: Array @@ -90,7 +151,7 @@ export function isDataModel(item: unknown): item is DataModel { export interface DataModelAttribute extends AstNode { readonly $container: DataModel; - args: Array + args: Array decl: Reference } @@ -115,7 +176,7 @@ export function isDataModelField(item: unknown): item is DataModelField { export interface DataModelFieldAttribute extends AstNode { readonly $container: DataModelField; - args: Array + args: Array decl: Reference } @@ -201,7 +262,7 @@ export function isFunction(item: unknown): item is Function { } export interface FunctionParam extends AstNode { - readonly $container: Attribute | Function; + readonly $container: Function; name: string type: FunctionParamType } @@ -226,8 +287,8 @@ export function isFunctionParamType(item: unknown): item is FunctionParamType { } export interface InvocationExpr extends AstNode { - readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; - args: Array + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; + args: Array function: Reference } @@ -238,7 +299,7 @@ export function isInvocationExpr(item: unknown): item is InvocationExpr { } export interface LiteralExpr extends AstNode { - readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; value: boolean | number | string } @@ -249,7 +310,7 @@ export function isLiteralExpr(item: unknown): item is LiteralExpr { } export interface MemberAccessExpr extends AstNode { - readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; member: Reference operand: Expression } @@ -270,8 +331,32 @@ export function isModel(item: unknown): item is Model { return reflection.isInstance(item, Model); } +export interface NullExpr extends AstNode { + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; + value: string +} + +export const NullExpr = 'NullExpr'; + +export function isNullExpr(item: unknown): item is NullExpr { + return reflection.isInstance(item, NullExpr); +} + +export interface ReferenceArg extends AstNode { + readonly $container: ReferenceExpr; + name: 'sort' + value: 'Asc' | 'Desc' +} + +export const ReferenceArg = 'ReferenceArg'; + +export function isReferenceArg(item: unknown): item is ReferenceArg { + return reflection.isInstance(item, ReferenceArg); +} + export interface ReferenceExpr extends AstNode { - readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; + args: Array target: Reference } @@ -282,7 +367,7 @@ export function isReferenceExpr(item: unknown): item is ReferenceExpr { } export interface ThisExpr extends AstNode { - readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; value: string } @@ -293,7 +378,7 @@ export function isThisExpr(item: unknown): item is ThisExpr { } export interface UnaryExpr extends AstNode { - readonly $container: ArrayExpr | BinaryExpr | DataModelAttribute | DataModelFieldAttribute | DataSourceField | Function | InvocationExpr | MemberAccessExpr | UnaryExpr; + readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; arg: Expression operator: '!' | '+' | '-' } @@ -304,14 +389,14 @@ export function isUnaryExpr(item: unknown): item is UnaryExpr { return reflection.isInstance(item, UnaryExpr); } -export type ZModelAstType = 'AbstractDeclaration' | 'ArrayExpr' | 'Attribute' | 'BinaryExpr' | 'DataModel' | 'DataModelAttribute' | 'DataModelField' | 'DataModelFieldAttribute' | 'DataModelFieldType' | 'DataSource' | 'DataSourceField' | 'Enum' | 'EnumField' | 'Expression' | 'Function' | 'FunctionParam' | 'FunctionParamType' | 'InvocationExpr' | 'LiteralExpr' | 'MemberAccessExpr' | 'Model' | 'ReferenceExpr' | 'ReferenceTarget' | 'ThisExpr' | 'TypeDeclaration' | 'UnaryExpr'; +export type ZModelAstType = 'AbstractDeclaration' | 'Argument' | 'ArrayExpr' | 'Attribute' | 'AttributeArg' | 'AttributeParam' | 'AttributeParamType' | 'BinaryExpr' | 'CascadeExpr' | 'DataModel' | 'DataModelAttribute' | 'DataModelField' | 'DataModelFieldAttribute' | 'DataModelFieldType' | 'DataSource' | 'DataSourceField' | 'Enum' | 'EnumField' | 'Expression' | 'Function' | 'FunctionParam' | 'FunctionParamType' | 'InvocationExpr' | 'LiteralExpr' | 'MemberAccessExpr' | 'Model' | 'NullExpr' | 'ReferenceArg' | 'ReferenceExpr' | 'ReferenceTarget' | 'ThisExpr' | 'TypeDeclaration' | 'UnaryExpr'; export type ZModelAstReference = 'DataModelAttribute:decl' | 'DataModelFieldAttribute:decl' | 'DataModelFieldType:reference' | 'FunctionParamType:reference' | 'InvocationExpr:function' | 'MemberAccessExpr:member' | 'ReferenceExpr:target'; export class ZModelAstReflection implements AstReflection { getAllTypes(): string[] { - return ['AbstractDeclaration', 'ArrayExpr', 'Attribute', 'BinaryExpr', 'DataModel', 'DataModelAttribute', 'DataModelField', 'DataModelFieldAttribute', 'DataModelFieldType', 'DataSource', 'DataSourceField', 'Enum', 'EnumField', 'Expression', 'Function', 'FunctionParam', 'FunctionParamType', 'InvocationExpr', 'LiteralExpr', 'MemberAccessExpr', 'Model', 'ReferenceExpr', 'ReferenceTarget', 'ThisExpr', 'TypeDeclaration', 'UnaryExpr']; + return ['AbstractDeclaration', 'Argument', 'ArrayExpr', 'Attribute', 'AttributeArg', 'AttributeParam', 'AttributeParamType', 'BinaryExpr', 'CascadeExpr', 'DataModel', 'DataModelAttribute', 'DataModelField', 'DataModelFieldAttribute', 'DataModelFieldType', 'DataSource', 'DataSourceField', 'Enum', 'EnumField', 'Expression', 'Function', 'FunctionParam', 'FunctionParamType', 'InvocationExpr', 'LiteralExpr', 'MemberAccessExpr', 'Model', 'NullExpr', 'ReferenceArg', 'ReferenceExpr', 'ReferenceTarget', 'ThisExpr', 'TypeDeclaration', 'UnaryExpr']; } isInstance(node: unknown, type: string): boolean { @@ -325,9 +410,11 @@ export class ZModelAstReflection implements AstReflection { switch (subtype) { case ArrayExpr: case BinaryExpr: + case CascadeExpr: case InvocationExpr: case LiteralExpr: case MemberAccessExpr: + case NullExpr: case ReferenceExpr: case ThisExpr: case UnaryExpr: { @@ -400,6 +487,23 @@ export class ZModelAstReflection implements AstReflection { ] }; } + case 'AttributeParam': { + return { + name: 'AttributeParam', + mandatory: [ + { name: 'positional', type: 'boolean' } + ] + }; + } + case 'AttributeParamType': { + return { + name: 'AttributeParamType', + mandatory: [ + { name: 'array', type: 'boolean' }, + { name: 'optional', type: 'boolean' } + ] + }; + } case 'DataModel': { return { name: 'DataModel', @@ -490,6 +594,14 @@ export class ZModelAstReflection implements AstReflection { ] }; } + case 'ReferenceExpr': { + return { + name: 'ReferenceExpr', + mandatory: [ + { name: 'args', type: 'array' } + ] + }; + } default: { return { name: type, diff --git a/packages/schema/src/language-server/generated/grammar.ts b/packages/schema/src/language-server/generated/grammar.ts index 1d3fc98dd..54e597ac7 100644 --- a/packages/schema/src/language-server/generated/grammar.ts +++ b/packages/schema/src/language-server/generated/grammar.ts @@ -238,13 +238,6 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "$refText": "STRING" }, "arguments": [] - }, - { - "$type": "RuleCall", - "rule": { - "$refText": "NULL" - }, - "arguments": [] } ] } @@ -343,24 +336,39 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, { "$type": "ParserRule", - "name": "ReferenceExpr", + "name": "NullExpr", "alternatives": { "$type": "Assignment", - "feature": "target", + "feature": "value", "operator": "=", "terminal": { - "$type": "CrossReference", - "type": { - "$refText": "ReferenceTarget" + "$type": "RuleCall", + "rule": { + "$refText": "NULL" }, - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] + "arguments": [] + } + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "CascadeExpr", + "alternatives": { + "$type": "Assignment", + "feature": "value", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "CASCADE" }, - "deprecatedSyntax": false + "arguments": [] } }, "definesHiddenTokens": false, @@ -370,6 +378,156 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "parameters": [], "wildcard": false }, + { + "$type": "ParserRule", + "name": "ReferenceExpr", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "target", + "operator": "=", + "terminal": { + "$type": "CrossReference", + "type": { + "$refText": "ReferenceTarget" + }, + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ID" + }, + "arguments": [] + }, + "deprecatedSyntax": false + } + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "(" + }, + { + "$type": "RuleCall", + "rule": { + "$refText": "ReferenceArgList" + }, + "arguments": [] + }, + { + "$type": "Keyword", + "value": ")" + } + ], + "cardinality": "?" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "ReferenceArgList", + "fragment": true, + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "args", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ReferenceArg" + }, + "arguments": [] + } + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "," + }, + { + "$type": "Assignment", + "feature": "args", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ReferenceArg" + }, + "arguments": [] + } + } + ], + "cardinality": "*" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "ReferenceArg", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "Keyword", + "value": "sort" + } + }, + { + "$type": "Keyword", + "value": ":" + }, + { + "$type": "Assignment", + "feature": "value", + "operator": "=", + "terminal": { + "$type": "Alternatives", + "elements": [ + { + "$type": "Keyword", + "value": "Asc" + }, + { + "$type": "Keyword", + "value": "Desc" + } + ] + } + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, { "$type": "ParserRule", "name": "InvocationExpr", @@ -1003,6 +1161,20 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, "arguments": [] }, + { + "$type": "RuleCall", + "rule": { + "$refText": "NullExpr" + }, + "arguments": [] + }, + { + "$type": "RuleCall", + "rule": { + "$refText": "CascadeExpr" + }, + "arguments": [] + }, { "$type": "RuleCall", "rule": { @@ -1061,7 +1233,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "terminal": { "$type": "RuleCall", "rule": { - "$refText": "Expression" + "$refText": "Argument" }, "arguments": [] } @@ -1080,7 +1252,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "terminal": { "$type": "RuleCall", "rule": { - "$refText": "Expression" + "$refText": "Argument" }, "arguments": [] } @@ -1096,6 +1268,55 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "parameters": [], "wildcard": false }, + { + "$type": "ParserRule", + "name": "Argument", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ID" + }, + "arguments": [] + } + }, + { + "$type": "Keyword", + "value": ":" + } + ], + "cardinality": "?" + }, + { + "$type": "Assignment", + "feature": "value", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "Expression" + }, + "arguments": [] + } + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, { "$type": "ParserRule", "name": "DataModel", @@ -1533,13 +1754,6 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "type": { "$refText": "TypeDeclaration" }, - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "ID" - }, - "arguments": [] - }, "deprecatedSyntax": false } } @@ -1600,7 +1814,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "terminal": { "$type": "RuleCall", "rule": { - "$refText": "FunctionParam" + "$refText": "AttributeParam" }, "arguments": [] } @@ -1619,7 +1833,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "terminal": { "$type": "RuleCall", "rule": { - "$refText": "FunctionParam" + "$refText": "AttributeParam" }, "arguments": [] } @@ -1643,6 +1857,108 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "parameters": [], "wildcard": false }, + { + "$type": "ParserRule", + "name": "AttributeParam", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "positional", + "operator": "?=", + "terminal": { + "$type": "Keyword", + "value": "_" + } + }, + { + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ID" + }, + "arguments": [] + } + }, + { + "$type": "Assignment", + "feature": "type", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "AttributeParamType" + }, + "arguments": [] + } + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "AttributeParamType", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Alternatives", + "elements": [ + { + "$type": "RuleCall", + "rule": { + "$refText": "BuiltinType" + }, + "arguments": [] + }, + { + "$type": "Assignment", + "feature": "type", + "operator": "=", + "terminal": { + "$type": "Keyword", + "value": "FieldReference" + } + } + ] + }, + { + "$type": "Assignment", + "feature": "array", + "operator": "?=", + "terminal": { + "$type": "Keyword", + "value": "[]" + } + }, + { + "$type": "Assignment", + "feature": "optional", + "operator": "?=", + "terminal": { + "$type": "Keyword", + "value": "?" + } + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, { "$type": "ParserRule", "name": "DataModelFieldAttribute", @@ -1675,7 +1991,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG { "$type": "RuleCall", "rule": { - "$refText": "ArgumentList" + "$refText": "AttributeArgList" }, "arguments": [], "cardinality": "?" @@ -1728,7 +2044,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG { "$type": "RuleCall", "rule": { - "$refText": "ArgumentList" + "$refText": "AttributeArgList" }, "arguments": [], "cardinality": "?" @@ -1749,6 +2065,104 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "parameters": [], "wildcard": false }, + { + "$type": "ParserRule", + "name": "AttributeArgList", + "fragment": true, + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "args", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "AttributeArg" + }, + "arguments": [] + } + }, + { + "$type": "Group", + "elements": [ + { + "$type": "Keyword", + "value": "," + }, + { + "$type": "Assignment", + "feature": "args", + "operator": "+=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "AttributeArg" + }, + "arguments": [] + } + } + ], + "cardinality": "*" + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, + { + "$type": "ParserRule", + "name": "AttributeArg", + "alternatives": { + "$type": "Group", + "elements": [ + { + "$type": "Group", + "elements": [ + { + "$type": "Assignment", + "feature": "name", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "ID" + }, + "arguments": [] + } + }, + { + "$type": "Keyword", + "value": ":" + } + ], + "cardinality": "?" + }, + { + "$type": "Assignment", + "feature": "value", + "operator": "=", + "terminal": { + "$type": "RuleCall", + "rule": { + "$refText": "Expression" + }, + "arguments": [] + } + } + ] + }, + "definesHiddenTokens": false, + "entry": false, + "fragment": false, + "hiddenTokens": [], + "parameters": [], + "wildcard": false + }, { "$type": "ParserRule", "name": "BuiltinType", @@ -1839,6 +2253,19 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "fragment": false, "hidden": false }, + { + "$type": "TerminalRule", + "name": "CASCADE", + "terminal": { + "$type": "CharacterRange", + "left": { + "$type": "Keyword", + "value": "Cascade" + } + }, + "fragment": false, + "hidden": false + }, { "$type": "TerminalRule", "name": "ID", diff --git a/packages/schema/src/language-server/stdlib.zmodel b/packages/schema/src/language-server/stdlib.zmodel index da8deb07b..a2a30366e 100644 --- a/packages/schema/src/language-server/stdlib.zmodel +++ b/packages/schema/src/language-server/stdlib.zmodel @@ -2,11 +2,12 @@ function env() String {} function auth() User {} attribute id() +attribute index() +attribute relation() attribute default() attribute createdAt() attribute updatedAt() attribute unique() -attribute cascade() attribute allow() attribute deny() attribute email() diff --git a/packages/schema/src/language-server/zmodel-linker.ts b/packages/schema/src/language-server/zmodel-linker.ts index a5c5c6eed..e22c486ce 100644 --- a/packages/schema/src/language-server/zmodel-linker.ts +++ b/packages/schema/src/language-server/zmodel-linker.ts @@ -16,7 +16,6 @@ import { CancellationToken } from 'vscode-jsonrpc'; import { AbstractDeclaration, isDataModel, - isEnumField, Function, FunctionParamType, DataModelFieldType, @@ -29,6 +28,10 @@ import { ReferenceExpr, UnaryExpr, BinaryExpr, + EnumField, + DataModelField, + FunctionParam, + isCascadeExpr, } from './generated/ast'; interface DefaultReference extends Reference { @@ -236,15 +239,20 @@ export class ZModelLinker extends DefaultLinker { ) { this.linkReference(node, 'target', document, extraScopes); + node.args.forEach((arg) => this.resolve(arg, document, extraScopes)); + if (node.target.ref) { // resolve type - if (isEnumField(node.target.ref)) { + if (node.target.ref.$type === EnumField) { this.resolveToBuiltinTypeOrDecl( node, node.target.ref.$container ); } else { - this.resolveToDeclaredType(node, node.target.ref.type); + this.resolveToDeclaredType( + node, + (node.target.ref as DataModelField | FunctionParam).type + ); } } } @@ -274,6 +282,11 @@ export class ZModelLinker extends DefaultLinker { } resolveLiteral(node: LiteralExpr) { + if (isCascadeExpr(node)) { + this.resolveToBuiltinTypeOrDecl(node, 'CASCADE'); + return; + } + const type = typeof node.value === 'string' ? 'String' diff --git a/packages/schema/src/language-server/zmodel.langium b/packages/schema/src/language-server/zmodel.langium index 0b547c5f6..b489de9b5 100644 --- a/packages/schema/src/language-server/zmodel.langium +++ b/packages/schema/src/language-server/zmodel.langium @@ -20,7 +20,7 @@ Expression: LogicalExpr; LiteralExpr: - value=(BOOLEAN | INT | STRING | NULL); + value=(BOOLEAN | INT | STRING); ArrayExpr: '[' (items+=Expression (',' items+=Expression)*)? ']'; @@ -30,8 +30,20 @@ type ReferenceTarget = FunctionParam | DataModelField | EnumField; ThisExpr: value=THIS; +NullExpr: + value=NULL; + +CascadeExpr: + value=CASCADE; + ReferenceExpr: - target=[ReferenceTarget:ID]; + target=[ReferenceTarget:ID] ('(' ReferenceArgList ')')?; + +fragment ReferenceArgList: + args+=ReferenceArg (',' args+=ReferenceArg)*; + +ReferenceArg: + name=('sort') ':' value=('Asc'| 'Desc'); InvocationExpr: function=[Function] '(' ArgumentList? ')'; @@ -93,6 +105,8 @@ LogicalExpr infers Expression: PrimaryExpr infers Expression: '(' Expression ')' | ThisExpr | + NullExpr | + CascadeExpr | LiteralExpr | InvocationExpr | ArrayExpr| @@ -100,7 +114,10 @@ PrimaryExpr infers Expression: UnaryExpr; fragment ArgumentList: - args+=Expression (',' args+=Expression)*; + args+=Argument (',' args+=Argument)*; + +Argument: + (name=ID ':')? value=Expression; // model DataModel: @@ -131,30 +148,40 @@ FunctionParam: name=ID type=FunctionParamType; FunctionParamType: - (BuiltinType | reference=[TypeDeclaration:ID]) (array?='[]')?; + (BuiltinType | reference=[TypeDeclaration]) (array?='[]')?; // attribute Attribute: - 'attribute' name=ID '(' (params+=FunctionParam (',' params+=FunctionParam)*)? ')'; + 'attribute' name=ID '(' (params+=AttributeParam (',' params+=AttributeParam)*)? ')'; + +AttributeParam: + positional?='_' name=ID type=AttributeParamType; + +AttributeParamType: + (BuiltinType | type='FieldReference') array?='[]' optional?='?'; type TypeDeclaration = DataModel | Enum; DataModelFieldAttribute: - '@' decl=[Attribute] ('(' ArgumentList? ')')?; + '@' decl=[Attribute] ('(' AttributeArgList? ')')?; DataModelAttribute: - '@@' decl=[Attribute] ('(' ArgumentList? ')')?; + '@@' decl=[Attribute] ('(' AttributeArgList? ')')?; + +fragment AttributeArgList: + args+=AttributeArg (',' args+=AttributeArg)*; + +AttributeArg: + (name=ID ':')? value=Expression; fragment BuiltinType: type=('String'|'Boolean'|'Int'|'DateTime'|'JSON'); -// QualifiedName returns string: -// ID ('.' ID)*; - hidden terminal WS: /\s+/; terminal BOOLEAN returns boolean: /true|false/; terminal NULL: 'null'; terminal THIS: 'this'; +terminal CASCADE: 'Cascade'; terminal ID: /[_a-zA-Z][\w_]*/; terminal STRING: /"[^"]*"|'[^']*'/; terminal INT returns number: /[+-]?[0-9]+/; diff --git a/packages/schema/src/utils/indent-string.ts b/packages/schema/src/utils/indent-string.ts new file mode 100644 index 000000000..d3e44d57b --- /dev/null +++ b/packages/schema/src/utils/indent-string.ts @@ -0,0 +1,41 @@ +// https://github.com/sindresorhus/indent-string + +export default function indentString( + string: string, + count = 1, + options: { indent?: string; includeEmptyLines?: boolean } = {} +) { + const { indent = ' ', includeEmptyLines = false } = options; + + if (typeof string !== 'string') { + throw new TypeError( + `Expected \`input\` to be a \`string\`, got \`${typeof string}\`` + ); + } + + if (typeof count !== 'number') { + throw new TypeError( + `Expected \`count\` to be a \`number\`, got \`${typeof count}\`` + ); + } + + if (count < 0) { + throw new RangeError( + `Expected \`count\` to be at least 0, got \`${count}\`` + ); + } + + if (typeof indent !== 'string') { + throw new TypeError( + `Expected \`options.indent\` to be a \`string\`, got \`${typeof indent}\`` + ); + } + + if (count === 0) { + return string; + } + + const regex = includeEmptyLines ? /^/gm : /^(?!\s*$)/gm; + + return string.replace(regex, indent.repeat(count)); +} diff --git a/packages/schema/syntaxes/zmodel.tmLanguage.json b/packages/schema/syntaxes/zmodel.tmLanguage.json index 552dee1a3..5e3743470 100644 --- a/packages/schema/syntaxes/zmodel.tmLanguage.json +++ b/packages/schema/syntaxes/zmodel.tmLanguage.json @@ -10,7 +10,7 @@ }, { "name": "keyword.control.zmodel", - "match": "\\b(attribute|Boolean|datasource|DateTime|enum|function|Int|JSON|model|String)\\b" + "match": "\\b(Asc|attribute|Boolean|datasource|DateTime|Desc|enum|FieldReference|function|Int|JSON|model|sort|String)\\b" }, { "name": "string.quoted.double.zmodel", diff --git a/packages/schema/tests/parser.test.ts b/packages/schema/tests/parser.test.ts index a076992d9..6a02f8757 100644 --- a/packages/schema/tests/parser.test.ts +++ b/packages/schema/tests/parser.test.ts @@ -1,14 +1,15 @@ import { - ArrayExpr, BinaryExpr, - ReferenceExpr, LiteralExpr, - UnaryExpr, InvocationExpr, DataSource, - Enum, DataModel, Function, + AttributeArg, + Enum, + UnaryExpr, + ReferenceExpr, + ArrayExpr, } from '../src/language-server/generated/ast'; import { parse } from './utils'; @@ -37,7 +38,7 @@ describe('Basic Tests', () => { expect((ds.fields[1].value as InvocationExpr).function.ref?.name).toBe( 'env' ); - expect((ds.fields[1].value as InvocationExpr).args[0].$type).toBe( + expect((ds.fields[1].value as InvocationExpr).args[0].value.$type).toBe( LiteralExpr ); }); @@ -54,28 +55,17 @@ describe('Basic Tests', () => { } `; const doc = await parse(content); - const enumDecl = doc.declarations[0] as Enum; - expect(enumDecl).toEqual( - expect.objectContaining({ - name: 'UserRole', - fields: expect.arrayContaining([ - expect.objectContaining({ - name: 'USER', - }), - expect.objectContaining({ - name: 'ADMIN', - }), - ]), - }) + const enumDecl = doc.declarations[0]; + expect(enumDecl.name).toBe('UserRole'); + expect((enumDecl as Enum).fields.map((f) => f.name)).toEqual( + expect.arrayContaining(['USER', 'ADMIN']) ); const model = doc.declarations[1] as DataModel; expect(model.fields[0].type.reference?.ref?.name).toBe('UserRole'); - const attrVal = model.fields[0].attributes[0].args[0] as ReferenceExpr; - expect(attrVal.$type).toBe(ReferenceExpr); - expect(attrVal.target.ref?.name).toBe('USER'); - expect((attrVal.target.ref?.$container as Enum).name).toBe('UserRole'); + const attrVal = model.fields[0].attributes[0].args[0] as AttributeArg; + expect((attrVal.value as ReferenceExpr).target.ref?.name).toBe('USER'); }); it('model field types', async () => { @@ -125,12 +115,8 @@ describe('Basic Tests', () => { const doc = await parse(content); const model = doc.declarations[0] as DataModel; expect(model.fields[0].attributes[0].decl.ref?.name).toBe('id'); - expect(model.fields[1].attributes[0]).toEqual( - expect.objectContaining({ - args: expect.arrayContaining([ - expect.objectContaining({ value: false }), - ]), - }) + expect(model.fields[1].attributes[0].args[0].value.$type).toBe( + LiteralExpr ); expect(model.fields[1].attributes[1].decl.ref?.name).toBe('unique'); }); @@ -141,17 +127,44 @@ describe('Basic Tests', () => { a String b String @@unique([a, b]) + @@unique([a(sort: Asc), b]) + @@unique(b(sort: Desc)) } `; const doc = await parse(content); const model = doc.declarations[0] as DataModel; - expect(model.attributes).toHaveLength(1); + expect(model.attributes).toHaveLength(3); expect(model.attributes[0].decl.ref?.name).toBe('unique'); expect( - (model.attributes[0].args[0] as ArrayExpr).items.map( - (item: any) => item.target?.ref?.name + (model.attributes[0].args[0].value as ArrayExpr).items.map( + (item) => (item as ReferenceExpr).target.ref?.name ) ).toEqual(expect.arrayContaining(['a', 'b'])); + + expect( + ( + (model.attributes[1].args[0].value as ArrayExpr) + .items[0] as ReferenceExpr + ).args[0] + ).toEqual( + expect.objectContaining({ + name: 'sort', + value: 'Asc', + }) + ); + + expect( + (model.attributes[2].args[0].value as ReferenceExpr).target.ref + ?.name + ).toBe('b'); + expect( + (model.attributes[2].args[0].value as ReferenceExpr).args[0] + ).toEqual( + expect.objectContaining({ + name: 'sort', + value: 'Desc', + }) + ); }); it('model relation', async () => { @@ -163,7 +176,7 @@ describe('Basic Tests', () => { model Post { id String - owner User @cascade + owner User @relation(references: [id], onDelete: Cascade, onUpdate: Cascade) } `; const doc = await parse(content); @@ -188,19 +201,31 @@ describe('Basic Tests', () => { const model = doc.declarations[0] as DataModel; const attrs = model.attributes; - expect(attrs[0].args[0].$type).toBe(UnaryExpr); - expect((attrs[0].args[0] as UnaryExpr).arg.$type).toBe(ReferenceExpr); + expect(attrs[0].args[0].value.$type).toBe(UnaryExpr); + expect((attrs[0].args[0].value as UnaryExpr).arg.$type).toBe( + ReferenceExpr + ); - expect(attrs[1].args[0].$type).toBe(BinaryExpr); - expect((attrs[1].args[0] as BinaryExpr).left.$type).toBe(ReferenceExpr); - expect((attrs[1].args[0] as BinaryExpr).right.$type).toBe(LiteralExpr); + expect(attrs[1].args[0].value.$type).toBe(BinaryExpr); + expect((attrs[1].args[0].value as BinaryExpr).left.$type).toBe( + ReferenceExpr + ); + expect((attrs[1].args[0].value as BinaryExpr).right.$type).toBe( + LiteralExpr + ); - expect(attrs[1].args[0].$type).toBe(BinaryExpr); - expect((attrs[1].args[0] as BinaryExpr).left.$type).toBe(ReferenceExpr); - expect((attrs[1].args[0] as BinaryExpr).right.$type).toBe(LiteralExpr); + expect(attrs[1].args[0].value.$type).toBe(BinaryExpr); + expect((attrs[1].args[0].value as BinaryExpr).left.$type).toBe( + ReferenceExpr + ); + expect((attrs[1].args[0].value as BinaryExpr).right.$type).toBe( + LiteralExpr + ); - expect(attrs[2].args[0].$type).toBe(BinaryExpr); - expect((attrs[2].args[0] as BinaryExpr).left.$type).toBe(BinaryExpr); + expect(attrs[2].args[0].value.$type).toBe(BinaryExpr); + expect((attrs[2].args[0].value as BinaryExpr).left.$type).toBe( + BinaryExpr + ); }); it('policy expression precedence', async () => { @@ -218,59 +243,70 @@ describe('Basic Tests', () => { const doc = await parse(content); const attrs = (doc.declarations[0] as DataModel).attributes; - expect(attrs[0].args[0].$type).toBe(BinaryExpr); + expect(attrs[0].args[0].value.$type).toBe(BinaryExpr); // 1: a + b * 2 > 0 // > - expect((attrs[0].args[0] as BinaryExpr).operator).toBe('>'); + expect((attrs[0].args[0].value as BinaryExpr).operator).toBe('>'); // a + b * 2 - expect((attrs[0].args[0] as BinaryExpr).left.$type).toBe(BinaryExpr); + expect((attrs[0].args[0].value as BinaryExpr).left.$type).toBe( + BinaryExpr + ); // 0 - expect((attrs[0].args[0] as BinaryExpr).right.$type).toBe(LiteralExpr); + expect((attrs[0].args[0].value as BinaryExpr).right.$type).toBe( + LiteralExpr + ); // + expect( - ((attrs[0].args[0] as BinaryExpr).left as BinaryExpr).operator + ((attrs[0].args[0].value as BinaryExpr).left as BinaryExpr).operator ).toBe('+'); // a expect( - ((attrs[0].args[0] as BinaryExpr).left as BinaryExpr).left.$type + ((attrs[0].args[0].value as BinaryExpr).left as BinaryExpr).left + .$type ).toBe(ReferenceExpr); // b * 2 expect( - ((attrs[0].args[0] as BinaryExpr).left as BinaryExpr).right.$type + ((attrs[0].args[0].value as BinaryExpr).left as BinaryExpr).right + .$type ).toBe(BinaryExpr); // 2: (a + b) * 2 > 0 // > - expect((attrs[1].args[0] as BinaryExpr).operator).toBe('>'); + expect((attrs[1].args[0].value as BinaryExpr).operator).toBe('>'); // (a + b) * 2 - expect((attrs[1].args[0] as BinaryExpr).left.$type).toBe(BinaryExpr); + expect((attrs[1].args[0].value as BinaryExpr).left.$type).toBe( + BinaryExpr + ); // 0 - expect((attrs[1].args[0] as BinaryExpr).right.$type).toBe(LiteralExpr); + expect((attrs[1].args[0].value as BinaryExpr).right.$type).toBe( + LiteralExpr + ); // * expect( - ((attrs[1].args[0] as BinaryExpr).left as BinaryExpr).operator + ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr).operator ).toBe('*'); // (a + b) expect( - ((attrs[1].args[0] as BinaryExpr).left as BinaryExpr).left.$type + ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr).left + .$type ).toBe(BinaryExpr); // a expect( ( - ((attrs[1].args[0] as BinaryExpr).left as BinaryExpr) + ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr) .left as BinaryExpr ).left.$type ).toBe(ReferenceExpr); @@ -278,14 +314,15 @@ describe('Basic Tests', () => { // b expect( ( - ((attrs[1].args[0] as BinaryExpr).left as BinaryExpr) + ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr) .left as BinaryExpr ).right.$type ).toBe(ReferenceExpr); // 2 expect( - ((attrs[1].args[0] as BinaryExpr).left as BinaryExpr).right.$type + ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr).right + .$type ).toBe(LiteralExpr); }); @@ -323,7 +360,7 @@ describe('Basic Tests', () => { expect(bar.params[0].type.reference?.ref?.name).toBe('N'); expect(bar.params[0].type.array).toBeTruthy(); - expect(model.attributes[0].args[0].$type).toBe(InvocationExpr); + expect(model.attributes[0].args[0].value.$type).toBe(InvocationExpr); }); it('member access', async () => { diff --git a/packages/schema/tests/todo-sample.test.ts b/packages/schema/tests/todo-sample.test.ts index 5619027bc..1f3b255d8 100644 --- a/packages/schema/tests/todo-sample.test.ts +++ b/packages/schema/tests/todo-sample.test.ts @@ -42,8 +42,8 @@ describe('Basic Tests', () => { id String @id createdAt DateTime @createdAt updatedAt DateTime @updatedAt - space Space @cascade - user User @cascade + space Space @relation(references: [id], onDelete: Cascade) + user User @relation(references: [id], onDelete: Cascade) role SpaceUserRole todoLists TodoList[] @@ -83,8 +83,8 @@ describe('Basic Tests', () => { id String @id createdAt DateTime @createdAt updatedAt DateTime @updatedAt - space Space @cascade - owner User + space Space @relation(references: [id], onDelete: Cascade) + owner User @relation(references: [id], onDelete: Cascade) title String @length(1, 20) private Boolean @default(false) todos Todo[] @@ -103,8 +103,8 @@ describe('Basic Tests', () => { id String @id createdAt DateTime @createdAt updatedAt DateTime @updatedAt - owner User - todoList TodoList @cascade + owner User @relation(references: [id], onDelete: Cascade) + todoList TodoList @relation(references: [id], onDelete: Cascade) title String completedAt DateTime? @@ -115,6 +115,7 @@ describe('Basic Tests', () => { @@allow('all', todoList.owner == auth() || (todoList.space.members?[user == auth()] && !todoList.private)) } `; + await parse(content); }); }); diff --git a/packages/schema/tsconfig.json b/packages/schema/tsconfig.json index 7e1e74338..63c6576dc 100644 --- a/packages/schema/tsconfig.json +++ b/packages/schema/tsconfig.json @@ -11,7 +11,8 @@ "moduleResolution": "node", "esModuleInterop": true, "skipLibCheck": true, - "forceConsistentCasingInFileNames": true + "forceConsistentCasingInFileNames": true, + "baseUrl": "./src" }, "include": ["src/**/*.ts"], "exclude": ["out", "node_modules"] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 05919c30c..f36931f56 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,7 +3,10 @@ lockfileVersion: 5.4 importers: .: - specifiers: {} + specifiers: + '@zenstackhq/schema': workspace:* + dependencies: + '@zenstackhq/schema': link:packages/schema packages/runtime: specifiers: @@ -48,6 +51,7 @@ importers: ts-node: ^10.9.1 typescript: ^4.6.2 uuid: ^9.0.0 + vscode-jsonrpc: ^8.0.2 vscode-languageclient: ^7.0.0 vscode-languageserver: ^7.0.0 vscode-uri: ^3.0.2 @@ -57,6 +61,7 @@ importers: commander: 8.3.0 langium: 0.4.0 uuid: 9.0.0 + vscode-jsonrpc: 8.0.2 vscode-languageclient: 7.0.0 vscode-languageserver: 7.0.0 vscode-uri: 3.0.6 @@ -265,7 +270,7 @@ packages: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.19.0 + '@babel/types': 7.19.3 dev: true /@babel/helper-module-transforms/7.19.0: @@ -293,7 +298,7 @@ packages: resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.19.0 + '@babel/types': 7.19.3 dev: true /@babel/helper-split-export-declaration/7.18.6: @@ -630,7 +635,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.0.3 - '@types/node': 14.18.29 + '@types/node': 16.11.62 chalk: 4.1.2 jest-message-util: 29.0.3 jest-util: 29.0.3 @@ -651,14 +656,14 @@ packages: '@jest/test-result': 29.0.3 '@jest/transform': 29.0.3 '@jest/types': 29.0.3 - '@types/node': 14.18.29 + '@types/node': 16.11.62 ansi-escapes: 4.3.2 chalk: 4.1.2 ci-info: 3.4.0 exit: 0.1.2 graceful-fs: 4.2.10 jest-changed-files: 29.0.0 - jest-config: 29.0.3_johvxhudwcpndp4mle25vwrlq4 + jest-config: 29.0.3_uo4il2aklsrxuk4ro37qmnu2ge jest-haste-map: 29.0.3 jest-message-util: 29.0.3 jest-regex-util: 29.0.0 @@ -685,7 +690,7 @@ packages: dependencies: '@jest/fake-timers': 29.0.3 '@jest/types': 29.0.3 - '@types/node': 14.18.29 + '@types/node': 16.11.62 jest-mock: 29.0.3 dev: true @@ -712,7 +717,7 @@ packages: dependencies: '@jest/types': 29.0.3 '@sinonjs/fake-timers': 9.1.2 - '@types/node': 14.18.29 + '@types/node': 16.11.62 jest-message-util: 29.0.3 jest-mock: 29.0.3 jest-util: 29.0.3 @@ -745,7 +750,7 @@ packages: '@jest/transform': 29.0.3 '@jest/types': 29.0.3 '@jridgewell/trace-mapping': 0.3.15 - '@types/node': 14.18.29 + '@types/node': 16.11.62 chalk: 4.1.2 collect-v8-coverage: 1.0.1 exit: 0.1.2 @@ -834,7 +839,7 @@ packages: '@jest/schemas': 29.0.0 '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 14.18.29 + '@types/node': 16.11.62 '@types/yargs': 17.0.12 chalk: 4.1.2 dev: true @@ -890,7 +895,7 @@ packages: '@prisma/client': '>=2.26.0 || >=3' next-auth: ^4 dependencies: - '@prisma/client': 4.3.1_prisma@4.3.1 + '@prisma/client': 4.3.1 next-auth: 4.10.3_biqbaboplfbrettd7655fr4n2y dev: false @@ -1156,7 +1161,7 @@ packages: /@types/graceful-fs/4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: - '@types/node': 14.18.29 + '@types/node': 16.11.62 dev: true /@types/istanbul-lib-coverage/2.0.4: @@ -1194,6 +1199,10 @@ packages: resolution: {integrity: sha512-LhF+9fbIX4iPzhsRLpK5H7iPdvW8L4IwGciXQIOEcuF62+9nw/VQVsOViAOOGxY3OlOKGLFv0sWwJXdwQeTn6A==} dev: true + /@types/node/16.11.62: + resolution: {integrity: sha512-K/ggecSdwAAy2NUW4WKmF4Rc03GKbsfP+k326UWgckoS+Rzd2PaWbjk76dSmqdLQvLTJAO9axiTUJ6488mFsYQ==} + dev: true + /@types/prettier/2.7.0: resolution: {integrity: sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A==} dev: true @@ -2989,7 +2998,7 @@ packages: '@jest/expect': 29.0.3 '@jest/test-result': 29.0.3 '@jest/types': 29.0.3 - '@types/node': 14.18.29 + '@types/node': 16.11.62 chalk: 4.1.2 co: 4.6.0 dedent: 0.7.0 @@ -3076,6 +3085,46 @@ packages: - supports-color dev: true + /jest-config/29.0.3_uo4il2aklsrxuk4ro37qmnu2ge: + resolution: {integrity: sha512-U5qkc82HHVYe3fNu2CRXLN4g761Na26rWKf7CjM8LlZB3In1jadEkZdMwsE37rd9RSPV0NfYaCjHdk/gu3v+Ew==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + dependencies: + '@babel/core': 7.19.1 + '@jest/test-sequencer': 29.0.3 + '@jest/types': 29.0.3 + '@types/node': 16.11.62 + babel-jest: 29.0.3_@babel+core@7.19.1 + chalk: 4.1.2 + ci-info: 3.4.0 + deepmerge: 4.2.2 + glob: 7.2.3 + graceful-fs: 4.2.10 + jest-circus: 29.0.3 + jest-environment-node: 29.0.3 + jest-get-type: 29.0.0 + jest-regex-util: 29.0.0 + jest-resolve: 29.0.3 + jest-runner: 29.0.3 + jest-util: 29.0.3 + jest-validate: 29.0.3 + micromatch: 4.0.5 + parse-json: 5.2.0 + pretty-format: 29.0.3 + slash: 3.0.0 + strip-json-comments: 3.1.1 + ts-node: 10.9.1_ck2axrxkiif44rdbzjywaqjysa + transitivePeerDependencies: + - supports-color + dev: true + /jest-diff/29.0.3: resolution: {integrity: sha512-+X/AIF5G/vX9fWK+Db9bi9BQas7M9oBME7egU7psbn4jlszLFCu0dW63UgeE6cs/GANq4fLaT+8sGHQQ0eCUfg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -3111,7 +3160,7 @@ packages: '@jest/environment': 29.0.3 '@jest/fake-timers': 29.0.3 '@jest/types': 29.0.3 - '@types/node': 14.18.29 + '@types/node': 16.11.62 jest-mock: 29.0.3 jest-util: 29.0.3 dev: true @@ -3127,7 +3176,7 @@ packages: dependencies: '@jest/types': 29.0.3 '@types/graceful-fs': 4.1.5 - '@types/node': 14.18.29 + '@types/node': 16.11.62 anymatch: 3.1.2 fb-watchman: 2.0.2 graceful-fs: 4.2.10 @@ -3178,7 +3227,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.0.3 - '@types/node': 14.18.29 + '@types/node': 16.11.62 dev: true /jest-pnp-resolver/1.2.2_jest-resolve@29.0.3: @@ -3232,7 +3281,7 @@ packages: '@jest/test-result': 29.0.3 '@jest/transform': 29.0.3 '@jest/types': 29.0.3 - '@types/node': 14.18.29 + '@types/node': 16.11.62 chalk: 4.1.2 emittery: 0.10.2 graceful-fs: 4.2.10 @@ -3263,7 +3312,7 @@ packages: '@jest/test-result': 29.0.3 '@jest/transform': 29.0.3 '@jest/types': 29.0.3 - '@types/node': 14.18.29 + '@types/node': 16.11.62 chalk: 4.1.2 cjs-module-lexer: 1.2.2 collect-v8-coverage: 1.0.1 @@ -3319,7 +3368,7 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@jest/types': 29.0.3 - '@types/node': 14.18.29 + '@types/node': 16.11.62 chalk: 4.1.2 ci-info: 3.4.0 graceful-fs: 4.2.10 @@ -3344,7 +3393,7 @@ packages: dependencies: '@jest/test-result': 29.0.3 '@jest/types': 29.0.3 - '@types/node': 14.18.29 + '@types/node': 16.11.62 ansi-escapes: 4.3.2 chalk: 4.1.2 emittery: 0.10.2 @@ -3356,7 +3405,7 @@ packages: resolution: {integrity: sha512-Tl/YWUugQOjoTYwjKdfJWkSOfhufJHO5LhXTSZC3TRoQKO+fuXnZAdoXXBlpLXKGODBL3OvdUasfDD4PcMe6ng==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@types/node': 14.18.29 + '@types/node': 16.11.62 merge-stream: 2.0.0 supports-color: 8.1.1 dev: true @@ -4693,6 +4742,11 @@ packages: resolution: {integrity: sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==} engines: {node: '>=8.0.0 || >=10.0.0'} + /vscode-jsonrpc/8.0.2: + resolution: {integrity: sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==} + engines: {node: '>=14.0.0'} + dev: false + /vscode-languageclient/7.0.0: resolution: {integrity: sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg==} engines: {vscode: ^1.52.0} From f6fb3b084e92ccc0ab058286372a73e6a720a354 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Tue, 4 Oct 2022 11:25:14 +0800 Subject: [PATCH 02/15] WIP: prisma generator tests --- .vscode/launch.json | 7 +- packages/schema/package.json | 1 + packages/schema/src/cli/cli-util.ts | 57 +- packages/schema/src/cli/index.ts | 13 - packages/schema/src/generator/prisma/index.ts | 34 +- .../src/generator/prisma/prisma-builder.ts | 110 +- .../src/language-server/generated/ast.ts | 18 +- .../src/language-server/generated/grammar.ts | 42 - .../schema/src/language-server/stdlib.zmodel | 6 +- .../src/language-server/zmodel-index.ts | 33 + .../src/language-server/zmodel-linker.ts | 78 +- .../src/language-server/zmodel-module.ts | 5 + .../src/language-server/zmodel-scope.ts | 29 +- .../schema/src/language-server/zmodel.langium | 5 - packages/schema/src/utils/indent-string.ts | 2 +- packages/schema/tests/parser.test.ts | 26 +- packages/schema/tests/prisma-builder.test.ts | 139 +++ packages/schema/tests/sample-todo.test.ts | 11 + packages/schema/tests/todo-sample.test.ts | 121 --- packages/schema/tests/utils.ts | 15 +- pnpm-lock.yaml | 941 +++++++++++++++++- samples/todo-target/.env | 5 + samples/todo-target/.eslintrc.json | 3 + samples/todo-target/.gitignore | 36 + .../.zenstack/.prisma/index-browser.js | 0 .../.zenstack/.prisma/index.d.ts | 0 .../.zenstack/.prisma/index.js | 0 .../libquery_engine-darwin-arm64.dylib.node | Bin .../.zenstack/.prisma/package.json | 0 .../.zenstack/.prisma/runtime/edge.js | 0 .../.prisma/runtime/index-browser.d.ts | 0 .../.prisma/runtime/index-browser.js | 0 .../.zenstack/.prisma/runtime/index.d.ts | 0 .../.zenstack/.prisma/runtime/index.js | 0 .../.zenstack/.prisma/schema.prisma | 0 .../.zenstack/auth/authorize.ts | 0 .../.zenstack/auth/index.ts | 0 .../.zenstack/auth/next-auth-adapter.ts | 0 .../{todo => todo-target}/.zenstack/client.ts | 0 .../.zenstack/functions/index.ts | 0 .../.zenstack/functions/invite-user.ts | 0 .../.zenstack/hooks/index.ts | 0 .../.zenstack/hooks/request.ts | 0 .../.zenstack/hooks/todo-list.ts | 0 .../.zenstack/hooks/todo.ts | 0 .../.zenstack/hooks/user.ts | 0 .../{todo => todo-target}/.zenstack/index.ts | 0 .../20220926071545_initial/migration.sql | 0 .../.zenstack/migrations/migration_lock.toml | 0 .../.zenstack/schema.prisma | 0 .../.zenstack/server/data/index.ts | 0 .../.zenstack/server/data/todo-list.ts | 0 .../.zenstack/server/data/utils.ts | 0 .../.zenstack/server/function/index.ts | 0 .../.zenstack/server/function/invite-user.ts | 0 .../.zenstack/server/index.ts | 0 .../{todo => todo-target}/.zenstack/types.ts | 0 samples/todo-target/README.md | 34 + .../todo-target/components/AccessDenied.tsx | 20 + .../todo-target/components/LoginButton.tsx | 22 + samples/todo-target/functions/invite-user.ts | 21 + samples/todo-target/next.config.js | 7 + samples/todo-target/package.json | 37 + samples/todo-target/pages/_app.tsx | 13 + .../pages/api/auth/[...nextauth].ts | 51 + samples/todo-target/pages/api/hello.ts | 13 + .../todo-target/pages/api/zen/[...path].ts | 12 + samples/todo-target/pages/index.tsx | 106 ++ samples/todo-target/postcss.config.js | 6 + samples/todo-target/public/favicon.ico | Bin 0 -> 25931 bytes samples/todo-target/public/vercel.svg | 4 + samples/todo-target/schema.zmodel | 118 +++ samples/todo-target/styles/globals.css | 3 + samples/todo-target/tailwind.config.js | 11 + samples/todo-target/tsconfig.json | 29 + samples/todo-target/types/next-auth.d.ts | 14 + samples/todo-target/types/next.d.ts | 16 + samples/todo/.gitignore | 2 + samples/todo/schema.zmodel | 36 +- 79 files changed, 1975 insertions(+), 337 deletions(-) create mode 100644 packages/schema/src/language-server/zmodel-index.ts create mode 100644 packages/schema/tests/prisma-builder.test.ts create mode 100644 packages/schema/tests/sample-todo.test.ts delete mode 100644 packages/schema/tests/todo-sample.test.ts create mode 100644 samples/todo-target/.env create mode 100644 samples/todo-target/.eslintrc.json create mode 100644 samples/todo-target/.gitignore rename samples/{todo => todo-target}/.zenstack/.prisma/index-browser.js (100%) rename samples/{todo => todo-target}/.zenstack/.prisma/index.d.ts (100%) rename samples/{todo => todo-target}/.zenstack/.prisma/index.js (100%) rename samples/{todo => todo-target}/.zenstack/.prisma/libquery_engine-darwin-arm64.dylib.node (100%) rename samples/{todo => todo-target}/.zenstack/.prisma/package.json (100%) rename samples/{todo => todo-target}/.zenstack/.prisma/runtime/edge.js (100%) rename samples/{todo => todo-target}/.zenstack/.prisma/runtime/index-browser.d.ts (100%) rename samples/{todo => todo-target}/.zenstack/.prisma/runtime/index-browser.js (100%) rename samples/{todo => todo-target}/.zenstack/.prisma/runtime/index.d.ts (100%) rename samples/{todo => todo-target}/.zenstack/.prisma/runtime/index.js (100%) rename samples/{todo => todo-target}/.zenstack/.prisma/schema.prisma (100%) rename samples/{todo => todo-target}/.zenstack/auth/authorize.ts (100%) rename samples/{todo => todo-target}/.zenstack/auth/index.ts (100%) rename samples/{todo => todo-target}/.zenstack/auth/next-auth-adapter.ts (100%) rename samples/{todo => todo-target}/.zenstack/client.ts (100%) rename samples/{todo => todo-target}/.zenstack/functions/index.ts (100%) rename samples/{todo => todo-target}/.zenstack/functions/invite-user.ts (100%) rename samples/{todo => todo-target}/.zenstack/hooks/index.ts (100%) rename samples/{todo => todo-target}/.zenstack/hooks/request.ts (100%) rename samples/{todo => todo-target}/.zenstack/hooks/todo-list.ts (100%) rename samples/{todo => todo-target}/.zenstack/hooks/todo.ts (100%) rename samples/{todo => todo-target}/.zenstack/hooks/user.ts (100%) rename samples/{todo => todo-target}/.zenstack/index.ts (100%) rename samples/{todo => todo-target}/.zenstack/migrations/20220926071545_initial/migration.sql (100%) rename samples/{todo => todo-target}/.zenstack/migrations/migration_lock.toml (100%) rename samples/{todo => todo-target}/.zenstack/schema.prisma (100%) rename samples/{todo => todo-target}/.zenstack/server/data/index.ts (100%) rename samples/{todo => todo-target}/.zenstack/server/data/todo-list.ts (100%) rename samples/{todo => todo-target}/.zenstack/server/data/utils.ts (100%) rename samples/{todo => todo-target}/.zenstack/server/function/index.ts (100%) rename samples/{todo => todo-target}/.zenstack/server/function/invite-user.ts (100%) rename samples/{todo => todo-target}/.zenstack/server/index.ts (100%) rename samples/{todo => todo-target}/.zenstack/types.ts (100%) create mode 100644 samples/todo-target/README.md create mode 100644 samples/todo-target/components/AccessDenied.tsx create mode 100644 samples/todo-target/components/LoginButton.tsx create mode 100644 samples/todo-target/functions/invite-user.ts create mode 100644 samples/todo-target/next.config.js create mode 100644 samples/todo-target/package.json create mode 100644 samples/todo-target/pages/_app.tsx create mode 100644 samples/todo-target/pages/api/auth/[...nextauth].ts create mode 100644 samples/todo-target/pages/api/hello.ts create mode 100644 samples/todo-target/pages/api/zen/[...path].ts create mode 100644 samples/todo-target/pages/index.tsx create mode 100644 samples/todo-target/postcss.config.js create mode 100644 samples/todo-target/public/favicon.ico create mode 100644 samples/todo-target/public/vercel.svg create mode 100644 samples/todo-target/schema.zmodel create mode 100644 samples/todo-target/styles/globals.css create mode 100644 samples/todo-target/tailwind.config.js create mode 100644 samples/todo-target/tsconfig.json create mode 100644 samples/todo-target/types/next-auth.d.ts create mode 100644 samples/todo-target/types/next.d.ts diff --git a/.vscode/launch.json b/.vscode/launch.json index 4ccd03843..2ae775061 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,11 +6,14 @@ "version": "0.2.0", "configurations": [ { - "name": "Launch CLI", + "name": "Generate for Todo Sample", "program": "${workspaceFolder}/packages/schema/bin/cli", + "cwd": "${workspaceFolder}/packages/schema", "args": [ "generate", - "${workspaceFolder}/samples/todo/schema.zmodel" + "${workspaceFolder}/samples/todo/schema.zmodel", + "--destination", + "${workspaceFolder}/samples/todo/.zenstack" ], "request": "launch", "skipFiles": ["/**"], diff --git a/packages/schema/package.json b/packages/schema/package.json index 50a26fb6f..51ce8f57c 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -69,6 +69,7 @@ "vscode-uri": "^3.0.2" }, "devDependencies": { + "@prisma/internals": "^4.4.0", "@types/jest": "^29.0.3", "@types/node": "^14.18.29", "@types/tmp": "^0.2.3", diff --git a/packages/schema/src/cli/cli-util.ts b/packages/schema/src/cli/cli-util.ts index 53f6a949b..93e7cdb1c 100644 --- a/packages/schema/src/cli/cli-util.ts +++ b/packages/schema/src/cli/cli-util.ts @@ -4,10 +4,17 @@ import fs from 'fs'; import { AstNode, LangiumDocument, LangiumServices } from 'langium'; import { URI } from 'vscode-uri'; -export async function extractDocument(fileName: string, services: LangiumServices): Promise { +export async function extractDocument( + fileName: string, + services: LangiumServices +): Promise { const extensions = services.LanguageMetaData.fileExtensions; if (!extensions.includes(path.extname(fileName))) { - console.error(colors.yellow(`Please choose a file with one of these extensions: ${extensions}.`)); + console.error( + colors.yellow( + `Please choose a file with one of these extensions: ${extensions}.` + ) + ); process.exit(1); } @@ -16,16 +23,31 @@ export async function extractDocument(fileName: string, services: LangiumService process.exit(1); } - const document = services.shared.workspace.LangiumDocuments.getOrCreateDocument(URI.file(path.resolve(fileName))); - await services.shared.workspace.DocumentBuilder.build([document], { validationChecks: 'all' }); + const stdLib = + services.shared.workspace.LangiumDocuments.getOrCreateDocument( + URI.file(path.resolve('src/language-server/stdlib.zmodel')) + ); + const document = + services.shared.workspace.LangiumDocuments.getOrCreateDocument( + URI.file(path.resolve(fileName)) + ); + await services.shared.workspace.DocumentBuilder.build([stdLib, document], { + validationChecks: 'all', + }); - const validationErrors = (document.diagnostics ?? []).filter(e => e.severity === 1); + const validationErrors = (document.diagnostics ?? []).filter( + (e) => e.severity === 1 + ); if (validationErrors.length > 0) { console.error(colors.red('There are validation errors:')); for (const validationError of validationErrors) { - console.error(colors.red( - `line ${validationError.range.start.line + 1}: ${validationError.message} [${document.textDocument.getText(validationError.range)}]` - )); + console.error( + colors.red( + `line ${validationError.range.start.line + 1}: ${ + validationError.message + } [${document.textDocument.getText(validationError.range)}]` + ) + ); } process.exit(1); } @@ -33,19 +55,26 @@ export async function extractDocument(fileName: string, services: LangiumService return document; } -export async function extractAstNode(fileName: string, services: LangiumServices): Promise { +export async function extractAstNode( + fileName: string, + services: LangiumServices +): Promise { return (await extractDocument(fileName, services)).parseResult?.value as T; } interface FilePathData { - destination: string, - name: string + destination: string; + name: string; } -export function extractDestinationAndName(filePath: string, destination: string | undefined): FilePathData { +export function extractDestinationAndName( + filePath: string, + destination: string | undefined +): FilePathData { filePath = filePath.replace(/\..*$/, '').replace(/[.-]/g, ''); return { - destination: destination ?? path.join(path.dirname(filePath), 'generated'), - name: path.basename(filePath) + destination: + destination ?? path.join(path.dirname(filePath), 'generated'), + name: path.basename(filePath), }; } diff --git a/packages/schema/src/cli/index.ts b/packages/schema/src/cli/index.ts index 8610a981d..cafd72991 100644 --- a/packages/schema/src/cli/index.ts +++ b/packages/schema/src/cli/index.ts @@ -1,10 +1,8 @@ -import colors from 'colors'; import { Command } from 'commander'; import { Model } from '../language-server/generated/ast'; import { ZModelLanguageMetaData } from '../language-server/generated/module'; import { createZModelServices } from '../language-server/zmodel-module'; import { extractAstNode } from './cli-util'; -import { generateJavaScript } from './generator'; import PrismaGenerator from '../generator/prisma'; import { Context } from '../generator/types'; @@ -24,17 +22,6 @@ export const generateAction = async ( for (const generator of generators) { await generator.generate(context); } - - const generatedFilePath = generateJavaScript( - model, - fileName, - opts.destination - ); - console.log( - colors.green( - `JavaScript code generated successfully: ${generatedFilePath}` - ) - ); }; export type GenerateOptions = { diff --git a/packages/schema/src/generator/prisma/index.ts b/packages/schema/src/generator/prisma/index.ts index 79dcfd197..dceb4ba50 100644 --- a/packages/schema/src/generator/prisma/index.ts +++ b/packages/schema/src/generator/prisma/index.ts @@ -31,9 +31,19 @@ import { FunctionCall as PrismaFunctionCall, FunctionCallArg as PrismaFunctionCallArg, PrismaModel, + ModelFieldType, } from './prisma-builder'; const supportedProviders = ['postgresql', 'mysql', 'sqlite', 'sqlserver']; +const supportedAttrbutes = [ + 'id', + 'index', + 'relation', + 'default', + 'createdAt', + 'updatedAt', + 'unique', +]; export default class PrismaGenerator implements Generator { async generate(context: Context) { @@ -144,10 +154,10 @@ export default class PrismaGenerator implements Generator { isInvocationExpr(fieldValue) && fieldValue.function.ref?.name === 'env' && fieldValue.args.length === 1 && - this.isStringLiteral(fieldValue.args[0]) + this.isStringLiteral(fieldValue.args[0].value) ) { return new PrismaDataSourceUrl( - fieldValue.args[0].value as string, + fieldValue.args[0].value.value as string, true ); } else { @@ -173,21 +183,23 @@ export default class PrismaGenerator implements Generator { this.generateModelField(model, field); } - for (const attr of decl.attributes) { + for (const attr of decl.attributes.filter((attr) => + supportedAttrbutes.includes(attr.decl.ref?.name!) + )) { this.generateModelAttribute(model, attr); } } private generateModelField(model: PrismaDataModel, field: DataModelField) { - const type = { - type: (field.type.type || field.type.reference?.ref?.name)!, - array: field.type.array, - optional: field.type.optional, - }; - - const attributes = field.attributes.map((attr) => - this.makeFieldAttribute(attr) + const type = new ModelFieldType( + (field.type.type || field.type.reference?.ref?.name)!, + field.type.array, + field.type.optional ); + + const attributes = field.attributes + .filter((attr) => supportedAttrbutes.includes(attr.decl.ref?.name!)) + .map((attr) => this.makeFieldAttribute(attr)); model.addField(field.name, type, attributes); } diff --git a/packages/schema/src/generator/prisma/prisma-builder.ts b/packages/schema/src/generator/prisma/prisma-builder.ts index 5c491334c..efcb958a2 100644 --- a/packages/schema/src/generator/prisma/prisma-builder.ts +++ b/packages/schema/src/generator/prisma/prisma-builder.ts @@ -1,4 +1,4 @@ -import indentString from 'utils/indent-string'; +import indentString from '../../utils/indent-string'; export class PrismaModel { private datasources: DataSource[] = []; @@ -56,12 +56,15 @@ export class DataSource { ) {} toString() { - return `datasource ${this.name} {\n` + + return ( + `datasource ${this.name} {\n` + indentString(`provider="${this.provider}"\n`) + indentString(`url=${this.url}\n`) + - this.shadowDatabaseUrl - ? indentString(`shadowDatabaseurl=${this.shadowDatabaseUrl}\n`) - : '' + `}`; + (this.shadowDatabaseUrl + ? indentString(`shadowDatabaseurl=${this.shadowDatabaseUrl}\n`) + : '') + + `}` + ); } } @@ -82,7 +85,7 @@ export class Generator { toString() { return ( - `generator ${this.name} {` + + `generator ${this.name} {\n` + indentString(`provider = "${this.provider}"\n`) + indentString(`output = "${this.output}"\n`) + `}` @@ -97,23 +100,29 @@ export class Model { addField( name: string, - type: ModelFieldType, - attributes: ModelAttribute[] = [] + type: ModelFieldType | string, + attributes: FieldAttribute[] = [] ) { const field = new ModelField(name, type, attributes); this.fields.push(field); return field; } + addAttribute(name: string, args: AttributeArg[] = []) { + const attr = new ModelAttribute(name, args); + this.attributes.push(attr); + return attr; + } + toString() { return ( - `model ${this.name} {` + + `model ${this.name} {\n` + indentString( [...this.fields, ...this.attributes] .map((d) => d.toString()) .join('\n') ) + - `}` + `\n}` ); } } @@ -130,16 +139,24 @@ export type ScalarTypes = | 'Bytes' | 'Unsupported'; -export type ModelFieldType = { - type: ScalarTypes | string; - array?: boolean; - optional?: boolean; -}; +export class ModelFieldType { + constructor( + public type: ScalarTypes | string, + public array?: boolean, + public optional?: boolean + ) {} + + toString() { + return `${this.type}${this.array ? '[]' : ''}${ + this.optional ? '?' : '' + }`; + } +} export class ModelField { constructor( public name: string, - public type: ModelFieldType, + public type: ModelFieldType | string, public attributes: FieldAttribute[] = [] ) {} @@ -212,14 +229,59 @@ export class AttributeArgValue { | FieldReference | FunctionCall | AttributeArgValue[] - ) {} + ) { + switch (type) { + case 'String': + if (typeof value !== 'string') + throw new Error('Value must be string'); + break; + case 'Number': + if (typeof value !== 'number') + throw new Error('Value must be number'); + break; + case 'Boolean': + if (typeof value !== 'boolean') + throw new Error('Value must be boolean'); + break; + case 'Array': + if (!Array.isArray(value)) + throw new Error('Value must be array'); + break; + case 'FieldReference': + if ( + typeof value !== 'string' && + !(value instanceof FieldReference) + ) + throw new Error('Value must be string or FieldReference'); + break; + case 'FunctionCall': + if (!(value instanceof FunctionCall)) + throw new Error('Value must be FunctionCall'); + break; + } + } toString(): string { switch (this.type) { case 'String': return `"${this.value}"`; case 'Number': - case 'FieldReference': + return this.value.toString(); + case 'FieldReference': { + if (typeof this.value === 'string') { + return this.value; + } else { + const fr = this.value as FieldReference; + let r = fr.field; + if (fr.args.length > 0) { + r += + '(' + + fr.args.map((a) => a.toString()).join(',') + + ')'; + } + return r; + } + } case 'FunctionCall': return this.value.toString(); case 'Boolean': @@ -243,11 +305,15 @@ export class FieldReference { } export class FieldReferenceArg { - constructor(public name: 'sort', value: 'Asc' | 'Desc') {} + constructor(public name: 'sort', public value: 'Asc' | 'Desc') {} + + toString() { + return `${this.name}: ${this.value}`; + } } export class FunctionCall { - constructor(public func: string, public args: FunctionCallArg[]) {} + constructor(public func: string, public args: FunctionCallArg[] = []) {} toString() { return ( @@ -272,7 +338,9 @@ export class Enum { toString() { return ( - `enum ${this.name} {\n` + indentString(this.fields.join('\n')) + '}' + `enum ${this.name} {\n` + + indentString(this.fields.join('\n')) + + '\n}' ); } } diff --git a/packages/schema/src/language-server/generated/ast.ts b/packages/schema/src/language-server/generated/ast.ts index dea8475f8..edd0b2658 100644 --- a/packages/schema/src/language-server/generated/ast.ts +++ b/packages/schema/src/language-server/generated/ast.ts @@ -15,7 +15,7 @@ export function isAbstractDeclaration(item: unknown): item is AbstractDeclaratio return reflection.isInstance(item, AbstractDeclaration); } -export type Expression = ArrayExpr | BinaryExpr | CascadeExpr | InvocationExpr | LiteralExpr | MemberAccessExpr | NullExpr | ReferenceExpr | ThisExpr | UnaryExpr; +export type Expression = ArrayExpr | BinaryExpr | InvocationExpr | LiteralExpr | MemberAccessExpr | NullExpr | ReferenceExpr | ThisExpr | UnaryExpr; export const Expression = 'Expression'; @@ -125,17 +125,6 @@ export function isBinaryExpr(item: unknown): item is BinaryExpr { return reflection.isInstance(item, BinaryExpr); } -export interface CascadeExpr extends AstNode { - readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; - value: string -} - -export const CascadeExpr = 'CascadeExpr'; - -export function isCascadeExpr(item: unknown): item is CascadeExpr { - return reflection.isInstance(item, CascadeExpr); -} - export interface DataModel extends AstNode { readonly $container: Model; attributes: Array @@ -389,14 +378,14 @@ export function isUnaryExpr(item: unknown): item is UnaryExpr { return reflection.isInstance(item, UnaryExpr); } -export type ZModelAstType = 'AbstractDeclaration' | 'Argument' | 'ArrayExpr' | 'Attribute' | 'AttributeArg' | 'AttributeParam' | 'AttributeParamType' | 'BinaryExpr' | 'CascadeExpr' | 'DataModel' | 'DataModelAttribute' | 'DataModelField' | 'DataModelFieldAttribute' | 'DataModelFieldType' | 'DataSource' | 'DataSourceField' | 'Enum' | 'EnumField' | 'Expression' | 'Function' | 'FunctionParam' | 'FunctionParamType' | 'InvocationExpr' | 'LiteralExpr' | 'MemberAccessExpr' | 'Model' | 'NullExpr' | 'ReferenceArg' | 'ReferenceExpr' | 'ReferenceTarget' | 'ThisExpr' | 'TypeDeclaration' | 'UnaryExpr'; +export type ZModelAstType = 'AbstractDeclaration' | 'Argument' | 'ArrayExpr' | 'Attribute' | 'AttributeArg' | 'AttributeParam' | 'AttributeParamType' | 'BinaryExpr' | 'DataModel' | 'DataModelAttribute' | 'DataModelField' | 'DataModelFieldAttribute' | 'DataModelFieldType' | 'DataSource' | 'DataSourceField' | 'Enum' | 'EnumField' | 'Expression' | 'Function' | 'FunctionParam' | 'FunctionParamType' | 'InvocationExpr' | 'LiteralExpr' | 'MemberAccessExpr' | 'Model' | 'NullExpr' | 'ReferenceArg' | 'ReferenceExpr' | 'ReferenceTarget' | 'ThisExpr' | 'TypeDeclaration' | 'UnaryExpr'; export type ZModelAstReference = 'DataModelAttribute:decl' | 'DataModelFieldAttribute:decl' | 'DataModelFieldType:reference' | 'FunctionParamType:reference' | 'InvocationExpr:function' | 'MemberAccessExpr:member' | 'ReferenceExpr:target'; export class ZModelAstReflection implements AstReflection { getAllTypes(): string[] { - return ['AbstractDeclaration', 'Argument', 'ArrayExpr', 'Attribute', 'AttributeArg', 'AttributeParam', 'AttributeParamType', 'BinaryExpr', 'CascadeExpr', 'DataModel', 'DataModelAttribute', 'DataModelField', 'DataModelFieldAttribute', 'DataModelFieldType', 'DataSource', 'DataSourceField', 'Enum', 'EnumField', 'Expression', 'Function', 'FunctionParam', 'FunctionParamType', 'InvocationExpr', 'LiteralExpr', 'MemberAccessExpr', 'Model', 'NullExpr', 'ReferenceArg', 'ReferenceExpr', 'ReferenceTarget', 'ThisExpr', 'TypeDeclaration', 'UnaryExpr']; + return ['AbstractDeclaration', 'Argument', 'ArrayExpr', 'Attribute', 'AttributeArg', 'AttributeParam', 'AttributeParamType', 'BinaryExpr', 'DataModel', 'DataModelAttribute', 'DataModelField', 'DataModelFieldAttribute', 'DataModelFieldType', 'DataSource', 'DataSourceField', 'Enum', 'EnumField', 'Expression', 'Function', 'FunctionParam', 'FunctionParamType', 'InvocationExpr', 'LiteralExpr', 'MemberAccessExpr', 'Model', 'NullExpr', 'ReferenceArg', 'ReferenceExpr', 'ReferenceTarget', 'ThisExpr', 'TypeDeclaration', 'UnaryExpr']; } isInstance(node: unknown, type: string): boolean { @@ -410,7 +399,6 @@ export class ZModelAstReflection implements AstReflection { switch (subtype) { case ArrayExpr: case BinaryExpr: - case CascadeExpr: case InvocationExpr: case LiteralExpr: case MemberAccessExpr: diff --git a/packages/schema/src/language-server/generated/grammar.ts b/packages/schema/src/language-server/generated/grammar.ts index 54e597ac7..f4df248bf 100644 --- a/packages/schema/src/language-server/generated/grammar.ts +++ b/packages/schema/src/language-server/generated/grammar.ts @@ -356,28 +356,6 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "parameters": [], "wildcard": false }, - { - "$type": "ParserRule", - "name": "CascadeExpr", - "alternatives": { - "$type": "Assignment", - "feature": "value", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "CASCADE" - }, - "arguments": [] - } - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, { "$type": "ParserRule", "name": "ReferenceExpr", @@ -1168,13 +1146,6 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG }, "arguments": [] }, - { - "$type": "RuleCall", - "rule": { - "$refText": "CascadeExpr" - }, - "arguments": [] - }, { "$type": "RuleCall", "rule": { @@ -2253,19 +2224,6 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "fragment": false, "hidden": false }, - { - "$type": "TerminalRule", - "name": "CASCADE", - "terminal": { - "$type": "CharacterRange", - "left": { - "$type": "Keyword", - "value": "Cascade" - } - }, - "fragment": false, - "hidden": false - }, { "$type": "TerminalRule", "name": "ID", diff --git a/packages/schema/src/language-server/stdlib.zmodel b/packages/schema/src/language-server/stdlib.zmodel index a2a30366e..465d19dac 100644 --- a/packages/schema/src/language-server/stdlib.zmodel +++ b/packages/schema/src/language-server/stdlib.zmodel @@ -1,11 +1,15 @@ +enum ReferentialIntegrity { + Cascade +} + function env() String {} function auth() User {} +function now() DateTime {} attribute id() attribute index() attribute relation() attribute default() -attribute createdAt() attribute updatedAt() attribute unique() attribute allow() diff --git a/packages/schema/src/language-server/zmodel-index.ts b/packages/schema/src/language-server/zmodel-index.ts new file mode 100644 index 000000000..355e744bb --- /dev/null +++ b/packages/schema/src/language-server/zmodel-index.ts @@ -0,0 +1,33 @@ +import { + AstNodeDescription, + DefaultAstNodeDescriptionProvider, + interruptAndCheck, + LangiumDocument, + LangiumServices, + streamAllContents, +} from 'langium'; +import { CancellationToken } from 'vscode-languageserver'; +import { isEnumField } from './generated/ast'; + +export class ZModelDescriptionProvider extends DefaultAstNodeDescriptionProvider { + constructor(services: LangiumServices) { + super(services); + } + + async createDescriptions( + document: LangiumDocument, + cancelToken = CancellationToken.None + ): Promise { + const descr = await super.createDescriptions(document, cancelToken); + // add enum fields so they can be globally resolved across modules + for (const node of streamAllContents(document.parseResult.value)) { + await interruptAndCheck(cancelToken); + if (isEnumField(node)) { + await descr.push( + this.createDescription(node, node.name, document) + ); + } + } + return descr; + } +} diff --git a/packages/schema/src/language-server/zmodel-linker.ts b/packages/schema/src/language-server/zmodel-linker.ts index e22c486ce..ba19e67b4 100644 --- a/packages/schema/src/language-server/zmodel-linker.ts +++ b/packages/schema/src/language-server/zmodel-linker.ts @@ -31,7 +31,8 @@ import { EnumField, DataModelField, FunctionParam, - isCascadeExpr, + ThisExpr, + NullExpr, } from './generated/ast'; interface DefaultReference extends Reference { @@ -162,30 +163,20 @@ export class ZModelLinker extends DefaultLinker { this.resolveBinary(node as BinaryExpr, document, extraScopes); break; + case ThisExpr: + this.resolveThis(node as ThisExpr, document, extraScopes); + break; + + case NullExpr: + this.resolveNull(node as NullExpr, document, extraScopes); + break; + default: this.resolveDefault(node, document, extraScopes); break; } } - resolveDefault( - node: AstNode, - document: LangiumDocument, - extraScopes: ScopeProvider[] - ) { - for (const property of Object.keys(node)) { - if (!property.startsWith('$')) { - const value = (node as any)[property]; - if (isReference(value)) { - this.linkReference(node, property, document, extraScopes); - } - } - } - for (const child of streamContents(node)) { - this.resolve(child, document, extraScopes); - } - } - resolveBinary( node: BinaryExpr, document: LangiumDocument, @@ -238,7 +229,6 @@ export class ZModelLinker extends DefaultLinker { extraScopes: ScopeProvider[] ) { this.linkReference(node, 'target', document, extraScopes); - node.args.forEach((arg) => this.resolve(arg, document, extraScopes)); if (node.target.ref) { @@ -282,11 +272,6 @@ export class ZModelLinker extends DefaultLinker { } resolveLiteral(node: LiteralExpr) { - if (isCascadeExpr(node)) { - this.resolveToBuiltinTypeOrDecl(node, 'CASCADE'); - return; - } - const type = typeof node.value === 'string' ? 'String' @@ -351,6 +336,49 @@ export class ZModelLinker extends DefaultLinker { } } + resolveThis( + node: ThisExpr, + document: LangiumDocument, + extraScopes: ScopeProvider[] + ) { + let decl: AstNode | undefined = node.$container; + + while (decl && !isDataModel(decl)) { + decl = decl.$container; + } + + if (decl) { + this.resolveToBuiltinTypeOrDecl(node, decl); + } + } + + resolveNull( + node: NullExpr, + document: LangiumDocument, + extraScopes: ScopeProvider[] + ) { + // TODO: how to really resolve null? + this.resolveToBuiltinTypeOrDecl(node, 'Null'); + } + + resolveDefault( + node: AstNode, + document: LangiumDocument, + extraScopes: ScopeProvider[] + ) { + for (const property of Object.keys(node)) { + if (!property.startsWith('$')) { + const value = (node as any)[property]; + if (isReference(value)) { + this.linkReference(node, property, document, extraScopes); + } + } + } + for (const child of streamContents(node)) { + this.resolve(child, document, extraScopes); + } + } + // utils getResolvedType(node: AstNode) { diff --git a/packages/schema/src/language-server/zmodel-module.ts b/packages/schema/src/language-server/zmodel-module.ts index 14e7850ad..20603db5e 100644 --- a/packages/schema/src/language-server/zmodel-module.ts +++ b/packages/schema/src/language-server/zmodel-module.ts @@ -12,6 +12,7 @@ import { ZModelGeneratedModule, ZModelGeneratedSharedModule, } from './generated/module'; +import { ZModelDescriptionProvider } from './zmodel-index'; import { ZModelLinker } from './zmodel-linker'; import { ZModelScopeComputation } from './zmodel-scope'; import { ZModelValidationRegistry, ZModelValidator } from './zmodel-validator'; @@ -50,6 +51,10 @@ export const ZModelModule: Module< new ZModelValidationRegistry(services), ZModelValidator: () => new ZModelValidator(), }, + workspace: { + AstNodeDescriptionProvider: (services) => + new ZModelDescriptionProvider(services), + }, }; /** diff --git a/packages/schema/src/language-server/zmodel-scope.ts b/packages/schema/src/language-server/zmodel-scope.ts index 2d59b6a6b..a6fd1a28c 100644 --- a/packages/schema/src/language-server/zmodel-scope.ts +++ b/packages/schema/src/language-server/zmodel-scope.ts @@ -3,10 +3,8 @@ import { LangiumDocument, LangiumServices, PrecomputedScopes, - streamAllContents, } from 'langium'; import { CancellationToken } from 'vscode-jsonrpc'; -import { Model, isEnum, Enum, isReferenceExpr } from './generated/ast'; export class ZModelScopeComputation extends DefaultScopeComputation { constructor(services: LangiumServices) { @@ -17,30 +15,7 @@ export class ZModelScopeComputation extends DefaultScopeComputation { document: LangiumDocument, cancelToken = CancellationToken.None ): Promise { - const scopes = await super.computeScope(document, cancelToken); - - const model = document.parseResult.value as Model; - - const enumDecls = model.declarations.filter((d) => isEnum(d)) as Enum[]; - const enumFieldDescriptions = enumDecls - .map((d) => - d.fields.map((f) => - this.descriptions.createDescription(f, f.name, document) - ) - ) - .flat(); - - // add enum field names to scopes of containers of any ReferenceExpr so that - // fully qualified references can be resolved - const refContainers = streamAllContents(model) - .filter((node) => isReferenceExpr(node) && node.$container) - .map((node) => node.$container!) - .distinct(); - - refContainers.forEach((c) => { - enumFieldDescriptions.forEach((desc) => scopes.add(c, desc)); - }); - - return scopes; + // Dummy for now + return super.computeScope(document, cancelToken); } } diff --git a/packages/schema/src/language-server/zmodel.langium b/packages/schema/src/language-server/zmodel.langium index b489de9b5..bff86413d 100644 --- a/packages/schema/src/language-server/zmodel.langium +++ b/packages/schema/src/language-server/zmodel.langium @@ -33,9 +33,6 @@ ThisExpr: NullExpr: value=NULL; -CascadeExpr: - value=CASCADE; - ReferenceExpr: target=[ReferenceTarget:ID] ('(' ReferenceArgList ')')?; @@ -106,7 +103,6 @@ PrimaryExpr infers Expression: '(' Expression ')' | ThisExpr | NullExpr | - CascadeExpr | LiteralExpr | InvocationExpr | ArrayExpr| @@ -181,7 +177,6 @@ hidden terminal WS: /\s+/; terminal BOOLEAN returns boolean: /true|false/; terminal NULL: 'null'; terminal THIS: 'this'; -terminal CASCADE: 'Cascade'; terminal ID: /[_a-zA-Z][\w_]*/; terminal STRING: /"[^"]*"|'[^']*'/; terminal INT returns number: /[+-]?[0-9]+/; diff --git a/packages/schema/src/utils/indent-string.ts b/packages/schema/src/utils/indent-string.ts index d3e44d57b..715b9be93 100644 --- a/packages/schema/src/utils/indent-string.ts +++ b/packages/schema/src/utils/indent-string.ts @@ -2,7 +2,7 @@ export default function indentString( string: string, - count = 1, + count = 4, options: { indent?: string; includeEmptyLines?: boolean } = {} ) { const { indent = ' ', includeEmptyLines = false } = options; diff --git a/packages/schema/tests/parser.test.ts b/packages/schema/tests/parser.test.ts index 6a02f8757..d4d4eada1 100644 --- a/packages/schema/tests/parser.test.ts +++ b/packages/schema/tests/parser.test.ts @@ -11,7 +11,7 @@ import { ReferenceExpr, ArrayExpr, } from '../src/language-server/generated/ast'; -import { parse } from './utils'; +import { loadModel } from './utils'; describe('Basic Tests', () => { it('data source', async () => { @@ -21,7 +21,7 @@ describe('Basic Tests', () => { url = env('DATABASE_URL') } `; - const doc = await parse(content); + const doc = await loadModel(content); expect(doc.declarations).toHaveLength(1); const ds = doc.declarations[0] as DataSource; @@ -54,7 +54,7 @@ describe('Basic Tests', () => { role UserRole @default(USER) } `; - const doc = await parse(content); + const doc = await loadModel(content); const enumDecl = doc.declarations[0]; expect(enumDecl.name).toBe('UserRole'); expect((enumDecl as Enum).fields.map((f) => f.name)).toEqual( @@ -78,7 +78,7 @@ describe('Basic Tests', () => { metadata JSON } `; - const doc = await parse(content); + const doc = await loadModel(content); const model = doc.declarations[0] as DataModel; expect(model.fields).toHaveLength(5); expect(model.fields.map((f) => f.type.type)).toEqual( @@ -99,7 +99,7 @@ describe('Basic Tests', () => { tags String[] } `; - const doc = await parse(content); + const doc = await loadModel(content); const model = doc.declarations[0] as DataModel; expect(model.fields[0].type.optional).toBeTruthy(); expect(model.fields[1].type.array).toBeTruthy(); @@ -112,7 +112,7 @@ describe('Basic Tests', () => { activated Boolean @default(false) @unique } `; - const doc = await parse(content); + const doc = await loadModel(content); const model = doc.declarations[0] as DataModel; expect(model.fields[0].attributes[0].decl.ref?.name).toBe('id'); expect(model.fields[1].attributes[0].args[0].value.$type).toBe( @@ -131,7 +131,7 @@ describe('Basic Tests', () => { @@unique(b(sort: Desc)) } `; - const doc = await parse(content); + const doc = await loadModel(content); const model = doc.declarations[0] as DataModel; expect(model.attributes).toHaveLength(3); expect(model.attributes[0].decl.ref?.name).toBe('unique'); @@ -179,7 +179,7 @@ describe('Basic Tests', () => { owner User @relation(references: [id], onDelete: Cascade, onUpdate: Cascade) } `; - const doc = await parse(content); + const doc = await loadModel(content); const models = doc.declarations as DataModel[]; expect(models[0].fields[1].type.reference?.ref?.name === 'Post'); expect(models[1].fields[1].type.reference?.ref?.name === 'User'); @@ -197,7 +197,7 @@ describe('Basic Tests', () => { @@deny(a + b < 10) } `; - const doc = await parse(content); + const doc = await loadModel(content); const model = doc.declarations[0] as DataModel; const attrs = model.attributes; @@ -240,7 +240,7 @@ describe('Basic Tests', () => { @@deny(a == 0 || b != 0) } `; - const doc = await parse(content); + const doc = await loadModel(content); const attrs = (doc.declarations[0] as DataModel).attributes; expect(attrs[0].args[0].value.$type).toBe(BinaryExpr); @@ -346,7 +346,7 @@ describe('Basic Tests', () => { function bar(items N[]) Boolean { } `; - const doc = await parse(content); + const doc = await loadModel(content); const model = doc.declarations[0] as DataModel; const foo = doc.declarations[2] as Function; const bar = doc.declarations[3] as Function; @@ -383,7 +383,7 @@ describe('Basic Tests', () => { n.x < 0 } `; - await parse(content); + await loadModel(content); }); it('collection predicate', async () => { @@ -397,6 +397,6 @@ describe('Basic Tests', () => { x Int } `; - await parse(content); + await loadModel(content); }); }); diff --git a/packages/schema/tests/prisma-builder.test.ts b/packages/schema/tests/prisma-builder.test.ts new file mode 100644 index 000000000..ad7550709 --- /dev/null +++ b/packages/schema/tests/prisma-builder.test.ts @@ -0,0 +1,139 @@ +import { + DataSourceUrl, + PrismaModel, + FieldAttribute, + AttributeArg, + FunctionCall, + AttributeArgValue, + ModelFieldType, + FieldReference, + FieldReferenceArg, +} from '../src/generator/prisma/prisma-builder'; +import { getDMMF } from '@prisma/internals'; + +async function validate(model: PrismaModel) { + const content = model.toString(); + console.log(`Prisma content:\n${content}`); + try { + return await getDMMF({ datamodel: content }); + } catch (err) { + console.error(`Failed to load DMMF: ${err}`); + throw err; + } +} + +describe('Prisma Builder Tests', () => { + it('datasource', async () => { + let model = new PrismaModel(); + model.addDataSource( + 'db', + 'postgresql', + new DataSourceUrl('DATABASE_URL', true) + ); + await validate(model); + + model = new PrismaModel(); + model.addDataSource( + 'db', + 'postgresql', + new DataSourceUrl( + 'postgresql://postgres:abc123@localhost:5432/sample?schema=public', + false + ) + ); + await validate(model); + }); + + it('enum', async () => { + let model = new PrismaModel(); + model.addEnum('UserRole', ['USER', 'ADMIN']); + await validate(model); + }); + + it('generator', async () => { + let model = new PrismaModel(); + model.addGenerator('client', 'prisma-client-js', '.prisma'); + await validate(model); + }); + + it('model', async () => { + let model = new PrismaModel(); + const dm = model.addModel('User'); + dm.addField('id', 'String', [new FieldAttribute('id')]); + dm.addField('createdAt', 'DateTime', [ + new FieldAttribute('default', [ + new AttributeArg( + undefined, + new AttributeArgValue( + 'FunctionCall', + new FunctionCall('now') + ) + ), + ]), + ]); + await validate(model); + }); + + it('relation', async () => { + let model = new PrismaModel(); + const user = model.addModel('User'); + user.addField('id', 'String', [new FieldAttribute('id')]); + user.addField('posts', new ModelFieldType('Post', true)); + + const post = model.addModel('Post'); + post.addField('id', 'String', [new FieldAttribute('id')]); + post.addField('user', 'User', [ + new FieldAttribute('relation', [ + new AttributeArg( + 'fields', + new AttributeArgValue('Array', [ + new AttributeArgValue('FieldReference', 'userId'), + ]) + ), + new AttributeArg( + 'references', + new AttributeArgValue('Array', [ + new AttributeArgValue('FieldReference', 'id'), + ]) + ), + new AttributeArg( + 'onDelete', + new AttributeArgValue( + 'FieldReference', + new FieldReference('Cascade') + ) + ), + ]), + ]); + post.addField('userId', 'String'); + + await validate(model); + }); + + it('model attribute', async () => { + let model = new PrismaModel(); + const post = model.addModel('Post'); + post.addField('id', 'String', [new FieldAttribute('id')]); + post.addField('slug', 'String'); + post.addField('space', 'String'); + post.addAttribute('unique', [ + new AttributeArg( + 'fields', + new AttributeArgValue('Array', [ + new AttributeArgValue( + 'FieldReference', + new FieldReference('space') + ), + new AttributeArgValue( + 'FieldReference', + new FieldReference('slug', [ + new FieldReferenceArg('sort', 'Desc'), + ]) + ), + ]) + ), + ]); + + await validate(model); + }); +}); diff --git a/packages/schema/tests/sample-todo.test.ts b/packages/schema/tests/sample-todo.test.ts new file mode 100644 index 000000000..c9df1c8f4 --- /dev/null +++ b/packages/schema/tests/sample-todo.test.ts @@ -0,0 +1,11 @@ +import { loadModel } from './utils'; +import * as fs from 'fs'; + +describe('Basic Tests', () => { + it('sample todo schema', async () => { + const content = fs.readFileSync('../../samples/todo/schema.zmodel', { + encoding: 'utf-8', + }); + await loadModel(content); + }); +}); diff --git a/packages/schema/tests/todo-sample.test.ts b/packages/schema/tests/todo-sample.test.ts deleted file mode 100644 index 1f3b255d8..000000000 --- a/packages/schema/tests/todo-sample.test.ts +++ /dev/null @@ -1,121 +0,0 @@ -import { parse } from './utils'; - -describe('Basic Tests', () => { - it('sample todo schema', async () => { - const content = ` - /* - * A sample model for a collaborative Todo app - */ - - // Datasource - datasource db { - provider = 'postgresql' - url = env('DATABASE_URL') - } - - enum SpaceUserRole { - USER - ADMIN - } - - model Space { - id String @id - createdAt DateTime @createdAt - updatedAt DateTime @updatedAt - name String @length(1, 100) - slug String @unique @length(1, 20) - members SpaceUser[] - - // require login - @@deny('all', auth() == null) - // everyone can create a space - @@allow('create', true) - - // any user in the space can read the space - @@allow('read', members?[user == auth()]) - - // space admin can update and delete - @@allow('update,delete', members?[user == auth() && role == ADMIN]) - } - - model SpaceUser { - id String @id - createdAt DateTime @createdAt - updatedAt DateTime @updatedAt - space Space @relation(references: [id], onDelete: Cascade) - user User @relation(references: [id], onDelete: Cascade) - role SpaceUserRole - todoLists TodoList[] - - @@unique([user, space]) - - // require login - @@deny('all', auth() == null) - - // space admin can create/update/delete - @@allow('create,update,delete', space.members?[user == auth() && role == ADMIN]) - - // user can read entries for spaces which he's a member of - @@allow('read', space.members?[user == auth()]) - } - - model User { - id String @id - createdAt DateTime @createdAt - updatedAt DateTime @updatedAt - email String @unique @email - name String? @length(1, 100) - spaces SpaceUser[] - image String? @url - todoLists TodoList[] - - // can be created by anyone, even not logged in - @@allow('create', true) - - // can be read by users sharing any space - @@allow('read', spaces?[auth() == user]) - - // can only be updated and deleted by himeself - @@allow('update,delete', auth() == this) - } - - model TodoList { - id String @id - createdAt DateTime @createdAt - updatedAt DateTime @updatedAt - space Space @relation(references: [id], onDelete: Cascade) - owner User @relation(references: [id], onDelete: Cascade) - title String @length(1, 20) - private Boolean @default(false) - todos Todo[] - - // require login - @@deny('all', auth() == null) - - // can be read by owner or space members (only if not private) - @@allow('read', owner == auth() || (space.members?[user == auth()] && !private)) - - // can be created/updated/deleted by owner - @@allow('create,update,delete', owner == auth() && space.members?[user == auth()]) - } - - model Todo { - id String @id - createdAt DateTime @createdAt - updatedAt DateTime @updatedAt - owner User @relation(references: [id], onDelete: Cascade) - todoList TodoList @relation(references: [id], onDelete: Cascade) - title String - completedAt DateTime? - - // require login - @@deny('all', auth() == null) - - // owner has full access, also space members have full access (if the parent TodoList is not private) - @@allow('all', todoList.owner == auth() || (todoList.space.members?[user == auth()] && !todoList.private)) - } - `; - - await parse(content); - }); -}); diff --git a/packages/schema/tests/utils.ts b/packages/schema/tests/utils.ts index 7a835f207..bb4d19489 100644 --- a/packages/schema/tests/utils.ts +++ b/packages/schema/tests/utils.ts @@ -1,4 +1,3 @@ -import { DefaultLangiumDocumentFactory } from 'langium'; import { createZModelServices } from '../src/language-server/zmodel-module'; import { URI } from 'vscode-uri'; import * as fs from 'fs'; @@ -6,20 +5,16 @@ import * as path from 'path'; import { Model } from '../src/language-server/generated/ast'; import * as tmp from 'tmp'; -export async function parse(content: string) { +export async function loadModel(content: string) { const { name: docPath } = tmp.fileSync({ postfix: '.zmodel' }); fs.writeFileSync(docPath, content); const { shared } = createZModelServices(); - const factory = new DefaultLangiumDocumentFactory(shared); - const stdLib = factory.fromString( - fs.readFileSync('src/language-server/stdlib.zmodel', { - encoding: 'utf-8', - }), + const stdLib = shared.workspace.LangiumDocuments.getOrCreateDocument( URI.file(path.resolve('src/language-server/stdlib.zmodel')) ); - const doc = factory.fromString(content, URI.file(docPath)); - shared.workspace.LangiumDocuments.addDocument(stdLib); - shared.workspace.LangiumDocuments.addDocument(doc); + const doc = shared.workspace.LangiumDocuments.getOrCreateDocument( + URI.file(docPath) + ); await shared.workspace.DocumentBuilder.build([stdLib, doc], { validationChecks: 'all', }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f36931f56..750c6da5c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,6 +31,7 @@ importers: packages/schema: specifiers: + '@prisma/internals': ^4.4.0 '@types/jest': ^29.0.3 '@types/node': ^14.18.29 '@types/tmp': ^0.2.3 @@ -66,6 +67,7 @@ importers: vscode-languageserver: 7.0.0 vscode-uri: 3.0.6 devDependencies: + '@prisma/internals': 4.4.0 '@types/jest': 29.0.3 '@types/node': 14.18.29 '@types/tmp': 0.2.3 @@ -1044,6 +1046,49 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.13.0 + /@opentelemetry/api/1.2.0: + resolution: {integrity: sha512-0nBr+VZNKm9tvNDZFstI3Pq1fCTEDK5OZTnVKNvBNAKgd0yIvmwsP4m61rEv7ZP+tOUjWJhROpxK5MsnlF911g==} + engines: {node: '>=8.0.0'} + dev: true + + /@opentelemetry/core/1.7.0_@opentelemetry+api@1.2.0: + resolution: {integrity: sha512-AVqAi5uc8DrKJBimCTFUT4iFI+5eXpo4sYmGbQ0CypG0piOTHE2g9c5aSoTGYXu3CzOmJZf7pT6Xh+nwm5d6yQ==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.3.0' + dependencies: + '@opentelemetry/api': 1.2.0 + '@opentelemetry/semantic-conventions': 1.7.0 + dev: true + + /@opentelemetry/resources/1.7.0_@opentelemetry+api@1.2.0: + resolution: {integrity: sha512-u1M0yZotkjyKx8dj+46Sg5thwtOTBmtRieNXqdCRiWUp6SfFiIP0bI+1XK3LhuXqXkBXA1awJZaTqKduNMStRg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.3.0' + dependencies: + '@opentelemetry/api': 1.2.0 + '@opentelemetry/core': 1.7.0_@opentelemetry+api@1.2.0 + '@opentelemetry/semantic-conventions': 1.7.0 + dev: true + + /@opentelemetry/sdk-trace-base/1.7.0_@opentelemetry+api@1.2.0: + resolution: {integrity: sha512-Iz84C+FVOskmauh9FNnj4+VrA+hG5o+tkMzXuoesvSfunVSioXib0syVFeNXwOm4+M5GdWCuW632LVjqEXStIg==} + engines: {node: '>=14'} + peerDependencies: + '@opentelemetry/api': '>=1.0.0 <1.3.0' + dependencies: + '@opentelemetry/api': 1.2.0 + '@opentelemetry/core': 1.7.0_@opentelemetry+api@1.2.0 + '@opentelemetry/resources': 1.7.0_@opentelemetry+api@1.2.0 + '@opentelemetry/semantic-conventions': 1.7.0 + dev: true + + /@opentelemetry/semantic-conventions/1.7.0: + resolution: {integrity: sha512-FGBx/Qd09lMaqQcogCHyYrFEpTx4cAjeS+48lMIR12z7LdH+zofGDVQSubN59nL6IpubfKqTeIDu9rNO28iHVA==} + engines: {node: '>=14'} + dev: true + /@panva/hkdf/1.0.2: resolution: {integrity: sha512-MSAs9t3Go7GUkMhpKC44T58DJ5KGk2vBo+h1cqQeqlMfdGkxaVB78ZWpv9gYi/g2fa4sopag9gJsNvS8XGgWJA==} dev: false @@ -1075,6 +1120,37 @@ packages: prisma: 4.3.1 dev: false + /@prisma/debug/4.4.0: + resolution: {integrity: sha512-tpJqrvmA8VlQuaVAmkFzIU7Of6xk3kQ2DYV6bPJukDZ6xmnufT27EpU8TSIra4jGdzz7y/R0rxmuXSBp24ew5w==} + dependencies: + '@types/debug': 4.1.7 + debug: 4.3.4 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@prisma/engine-core/4.4.0: + resolution: {integrity: sha512-SwwfaBkQhw6EpwDK2X6+2w4Z9cfdQiZWC2Rmdp26JC4R1Q3i3Y/7GPgMSrwCJvSF9y0+nJ93Kyx7uq9xuIlSZQ==} + dependencies: + '@opentelemetry/api': 1.2.0 + '@opentelemetry/sdk-trace-base': 1.7.0_@opentelemetry+api@1.2.0 + '@prisma/debug': 4.4.0 + '@prisma/engines': 4.4.0 + '@prisma/generator-helper': 4.4.0 + '@prisma/get-platform': 4.4.0 + chalk: 4.1.2 + execa: 5.1.1 + get-stream: 6.0.1 + indent-string: 4.0.0 + new-github-issue-url: 0.2.1 + p-retry: 4.6.2 + strip-ansi: 6.0.1 + undici: 5.10.0 + transitivePeerDependencies: + - supports-color + dev: true + /@prisma/engines-version/4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b: resolution: {integrity: sha512-8yWpXkQRmiSfsi2Wb/ZS5D3RFbeu/btL9Pm/gdF4phB0Lo5KGsDFMxFMgaD64mwED2nHc8ZaEJg/+4Jymb9Znw==} dev: false @@ -1083,6 +1159,111 @@ packages: resolution: {integrity: sha512-4JF/uMaEDAPdcdZNOrnzE3BvrbGpjgV0FcPT3EVoi6I86fWkloqqxBt+KcK/+fIRR0Pxj66uGR9wVH8U1Y13JA==} requiresBuild: true + /@prisma/engines/4.4.0: + resolution: {integrity: sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==} + requiresBuild: true + dev: true + + /@prisma/fetch-engine/4.4.0: + resolution: {integrity: sha512-3a+f/HPvJl9XYj8IuX57/rHM8cYZuqS+R+jXx/ZPRwvELVlvVeE81GTTSMvtXguyfHXgKW7wKjiJqZm7tGw/WA==} + dependencies: + '@prisma/debug': 4.4.0 + '@prisma/get-platform': 4.4.0 + chalk: 4.1.2 + execa: 5.1.1 + find-cache-dir: 3.3.2 + hasha: 5.2.2 + http-proxy-agent: 5.0.0 + https-proxy-agent: 5.0.1 + make-dir: 3.1.0 + node-fetch: 2.6.7 + p-filter: 2.1.0 + p-map: 4.0.0 + p-retry: 4.6.2 + progress: 2.0.3 + rimraf: 3.0.2 + temp-dir: 2.0.0 + tempy: 1.0.1 + transitivePeerDependencies: + - encoding + - supports-color + dev: true + + /@prisma/generator-helper/4.4.0: + resolution: {integrity: sha512-6z5Tl+Cjk/WDWUMvpCOzhsK4Nkcb64zGoU/NePl3Z0tFR2RkfnBfnmJbpWdHr9HQYz7jO7LsTAyS5aWPjqeHKg==} + dependencies: + '@prisma/debug': 4.4.0 + '@types/cross-spawn': 6.0.2 + chalk: 4.1.2 + cross-spawn: 7.0.3 + transitivePeerDependencies: + - supports-color + dev: true + + /@prisma/get-platform/4.4.0: + resolution: {integrity: sha512-3m8Y07h9bZlfS98dh5/e2wS+5iJ3NLBOy3bv7zjGa2GI68EW5q3ncbtHHw9vk5G6epTO7YrM/PBFqQWc4fKvNA==} + dependencies: + '@prisma/debug': 4.4.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@prisma/internals/4.4.0: + resolution: {integrity: sha512-DvJ78z+HI6+5qA4SSHS/BRxR8m0aTIpJIhBbV/cY6m6kYgOvBjuf9slp+MqHpRR28eC5rgOS+e0DlN/tU+cxLg==} + dependencies: + '@prisma/debug': 4.4.0 + '@prisma/engine-core': 4.4.0 + '@prisma/engines': 4.4.0 + '@prisma/fetch-engine': 4.4.0 + '@prisma/generator-helper': 4.4.0 + '@prisma/get-platform': 4.4.0 + '@prisma/prisma-fmt-wasm': 4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6 + archiver: 5.3.1 + arg: 5.0.2 + chalk: 4.1.2 + checkpoint-client: 1.1.21 + cli-truncate: 2.1.0 + dotenv: 16.0.2 + escape-string-regexp: 4.0.0 + execa: 5.1.1 + find-up: 5.0.0 + fp-ts: 2.12.3 + fs-extra: 10.1.0 + fs-jetpack: 5.0.0 + global-dirs: 3.0.0 + globby: 11.1.0 + has-yarn: 2.1.0 + is-windows: 1.0.2 + is-wsl: 2.2.0 + make-dir: 3.1.0 + new-github-issue-url: 0.2.1 + node-fetch: 2.6.7 + open: 7.4.2 + ora: 5.4.1 + p-map: 4.0.0 + prompts: 2.4.2 + read-pkg-up: 7.0.1 + replace-string: 3.1.0 + resolve: 1.22.1 + rimraf: 3.0.2 + string-width: 4.2.3 + strip-ansi: 6.0.1 + strip-indent: 3.0.0 + temp-dir: 2.0.0 + temp-write: 4.0.0 + tempy: 1.0.1 + terminal-link: 2.1.1 + tmp: 0.2.1 + ts-pattern: 4.0.5 + transitivePeerDependencies: + - encoding + - supports-color + dev: true + + /@prisma/prisma-fmt-wasm/4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6: + resolution: {integrity: sha512-Hc2i5nfAt3nLDUkQNWJcKFJaA9Avd5zz6t85w9SW7P0vGtFXScQ+xIu6znbULr9bc0pgTWejY1We2u/7EMxHWw==} + dev: true + /@rushstack/eslint-patch/1.2.0: resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==} dev: true @@ -1109,6 +1290,11 @@ packages: tslib: 2.4.0 dev: false + /@tootallnate/once/2.0.0: + resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} + engines: {node: '>= 10'} + dev: true + /@tsconfig/node10/1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} dev: true @@ -1158,6 +1344,18 @@ packages: resolution: {integrity: sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==} dev: true + /@types/cross-spawn/6.0.2: + resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==} + dependencies: + '@types/node': 16.11.62 + dev: true + + /@types/debug/4.1.7: + resolution: {integrity: sha512-9AonUzyTjXXhEOa0DnqpzZi6VHlqKMswga9EXjpXnnqxwLtdvPPtlO8evrI5D9S6asFRCQ6v+wpiUKbw+vKqyg==} + dependencies: + '@types/ms': 0.7.31 + dev: true + /@types/graceful-fs/4.1.5: resolution: {integrity: sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw==} dependencies: @@ -1195,6 +1393,10 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true + /@types/ms/0.7.31: + resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} + dev: true + /@types/node/14.18.29: resolution: {integrity: sha512-LhF+9fbIX4iPzhsRLpK5H7iPdvW8L4IwGciXQIOEcuF62+9nw/VQVsOViAOOGxY3OlOKGLFv0sWwJXdwQeTn6A==} dev: true @@ -1203,6 +1405,10 @@ packages: resolution: {integrity: sha512-K/ggecSdwAAy2NUW4WKmF4Rc03GKbsfP+k326UWgckoS+Rzd2PaWbjk76dSmqdLQvLTJAO9axiTUJ6488mFsYQ==} dev: true + /@types/normalize-package-data/2.4.1: + resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} + dev: true + /@types/prettier/2.7.0: resolution: {integrity: sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A==} dev: true @@ -1225,6 +1431,10 @@ packages: csstype: 3.1.1 dev: true + /@types/retry/0.12.0: + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + dev: true + /@types/scheduler/0.16.2: resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} dev: true @@ -1458,6 +1668,23 @@ packages: hasBin: true dev: true + /agent-base/6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /aggregate-error/3.1.0: + resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} + engines: {node: '>=8'} + dependencies: + clean-stack: 2.2.0 + indent-string: 4.0.0 + dev: true + /ajv/6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} dependencies: @@ -1519,6 +1746,35 @@ packages: normalize-path: 3.0.0 picomatch: 2.3.1 + /archiver-utils/2.1.0: + resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} + engines: {node: '>= 6'} + dependencies: + glob: 7.2.3 + graceful-fs: 4.2.10 + lazystream: 1.0.1 + lodash.defaults: 4.2.0 + lodash.difference: 4.5.0 + lodash.flatten: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.union: 4.6.0 + normalize-path: 3.0.0 + readable-stream: 2.3.7 + dev: true + + /archiver/5.3.1: + resolution: {integrity: sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==} + engines: {node: '>= 10'} + dependencies: + archiver-utils: 2.1.0 + async: 3.2.4 + buffer-crc32: 0.2.13 + readable-stream: 3.6.0 + readdir-glob: 1.1.2 + tar-stream: 2.2.0 + zip-stream: 4.1.0 + dev: true + /arg/4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} dev: true @@ -1585,6 +1841,10 @@ packages: engines: {node: '>=8'} dev: true + /async/3.2.4: + resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==} + dev: true + /at-least-node/1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} @@ -1689,6 +1949,10 @@ packages: /balanced-match/1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + /base64-js/1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + dev: true + /bcryptjs/2.4.3: resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} dev: false @@ -1697,12 +1961,26 @@ packages: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} + /bl/4.1.0: + resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + dependencies: + buffer: 5.7.1 + inherits: 2.0.4 + readable-stream: 3.6.0 + dev: true + /brace-expansion/1.1.11: resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 + /brace-expansion/2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + /braces/3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} @@ -1732,10 +2010,21 @@ packages: node-int64: 0.4.0 dev: true + /buffer-crc32/0.2.13: + resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + dev: true + /buffer-from/1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} dev: true + /buffer/5.7.1: + resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + dependencies: + base64-js: 1.5.1 + ieee754: 1.2.1 + dev: true + /call-bind/1.0.2: resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} dependencies: @@ -1787,6 +2076,20 @@ packages: engines: {node: '>=10'} dev: true + /checkpoint-client/1.1.21: + resolution: {integrity: sha512-bcrcnJncn6uGhj06IIsWvUBPyJWK1ZezDbLCJ//IQEYXkUobhGvOOBlHe9K5x0ZMkAZGinPB4T+lTUmFz/acWQ==} + dependencies: + ci-info: 3.3.0 + env-paths: 2.2.1 + fast-write-atomic: 0.2.1 + make-dir: 3.1.0 + ms: 2.1.3 + node-fetch: 2.6.7 + uuid: 8.3.2 + transitivePeerDependencies: + - encoding + dev: true + /chevrotain/9.1.0: resolution: {integrity: sha512-A86/55so63HCfu0dgGg3j9u8uuuBOrSqly1OhBZxRu2x6sAKILLzfVjbGMw45kgier6lz45EzcjjWtTRgoT84Q==} dependencies: @@ -1808,6 +2111,10 @@ packages: optionalDependencies: fsevents: 2.3.2 + /ci-info/3.3.0: + resolution: {integrity: sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==} + dev: true + /ci-info/3.4.0: resolution: {integrity: sha512-t5QdPT5jq3o262DOQ8zA6E1tlH2upmUc4Hlvrbx1pGYJuiiHl7O7rvVNI+l8HTVhd/q3Qc9vqimkNk5yiXsAug==} dev: true @@ -1816,6 +2123,31 @@ packages: resolution: {integrity: sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==} dev: true + /clean-stack/2.2.0: + resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} + engines: {node: '>=6'} + dev: true + + /cli-cursor/3.1.0: + resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} + engines: {node: '>=8'} + dependencies: + restore-cursor: 3.1.0 + dev: true + + /cli-spinners/2.7.0: + resolution: {integrity: sha512-qu3pN8Y3qHNgE2AFweciB1IfMnmZ/fsNTEE+NOFjmGB2F/7rLhnhzppvpCnN4FovtP26k8lHyy9ptEbNwWFLzw==} + engines: {node: '>=6'} + dev: true + + /cli-truncate/2.1.0: + resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} + engines: {node: '>=8'} + dependencies: + slice-ansi: 3.0.0 + string-width: 4.2.3 + dev: true + /cliui/7.0.4: resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} dependencies: @@ -1824,6 +2156,11 @@ packages: wrap-ansi: 7.0.0 dev: true + /clone/1.0.4: + resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} + engines: {node: '>=0.8'} + dev: true + /co/4.6.0: resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} @@ -1881,6 +2218,20 @@ packages: engines: {node: '>= 12'} dev: false + /commondir/1.0.1: + resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} + dev: true + + /compress-commons/4.1.1: + resolution: {integrity: sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==} + engines: {node: '>= 10'} + dependencies: + buffer-crc32: 0.2.13 + crc32-stream: 4.0.2 + normalize-path: 3.0.0 + readable-stream: 3.6.0 + dev: true + /concat-map/0.0.1: resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} @@ -1916,6 +2267,24 @@ packages: requiresBuild: true dev: true + /core-util-is/1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: true + + /crc-32/1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true + dev: true + + /crc32-stream/4.0.2: + resolution: {integrity: sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==} + engines: {node: '>= 10'} + dependencies: + crc-32: 1.2.2 + readable-stream: 3.6.0 + dev: true + /create-require/1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} dev: true @@ -1929,6 +2298,11 @@ packages: which: 2.0.2 dev: true + /crypto-random-string/2.0.0: + resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} + engines: {node: '>=8'} + dev: true + /css-selector-tokenizer/0.8.0: resolution: {integrity: sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==} dependencies: @@ -2017,6 +2391,12 @@ packages: engines: {node: '>=0.10.0'} dev: true + /defaults/1.0.3: + resolution: {integrity: sha512-s82itHOnYrN0Ib8r+z7laQz3sdE+4FP3d9Q7VLO7U+KRT+CR0GsWuyHxzdAY82I7cXv0G/twrqomTJLOssO5HA==} + dependencies: + clone: 1.0.4 + dev: true + /define-properties/1.1.4: resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} engines: {node: '>= 0.4'} @@ -2028,6 +2408,20 @@ packages: /defined/1.0.0: resolution: {integrity: sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==} + /del/6.1.1: + resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} + engines: {node: '>=10'} + dependencies: + globby: 11.1.0 + graceful-fs: 4.2.10 + is-glob: 4.0.3 + is-path-cwd: 2.2.0 + is-path-inside: 3.0.3 + p-map: 4.0.0 + rimraf: 3.0.2 + slash: 3.0.0 + dev: true + /detect-newline/3.1.0: resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} engines: {node: '>=8'} @@ -2079,6 +2473,11 @@ packages: esutils: 2.0.3 dev: true + /dotenv/16.0.2: + resolution: {integrity: sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==} + engines: {node: '>=12'} + dev: true + /electron-to-chromium/1.4.257: resolution: {integrity: sha512-C65sIwHqNnPC2ADMfse/jWTtmhZMII+x6ADI9gENzrOiI7BpxmfKFE84WkIEl5wEg+7+SfIkwChDlsd1Erju2A==} @@ -2095,6 +2494,12 @@ packages: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} dev: true + /end-of-stream/1.4.4: + resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + dependencies: + once: 1.4.0 + dev: true + /enquirer/2.3.6: resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} engines: {node: '>=8.6'} @@ -2102,6 +2507,11 @@ packages: ansi-colors: 4.1.3 dev: true + /env-paths/2.2.1: + resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} + engines: {node: '>=6'} + dev: true + /error-ex/1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} dependencies: @@ -2522,6 +2932,10 @@ packages: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} dev: true + /fast-write-atomic/0.2.1: + resolution: {integrity: sha512-WvJe06IfNYlr+6cO3uQkdKdy3Cb1LlCJSF8zRs2eT8yuhdbSlR9nIt+TgQ92RUxiRrQm+/S7RARnMfCs5iuAjw==} + dev: true + /fastparse/1.1.2: resolution: {integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==} dev: false @@ -2550,6 +2964,15 @@ packages: dependencies: to-regex-range: 5.0.1 + /find-cache-dir/3.3.2: + resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} + engines: {node: '>=8'} + dependencies: + commondir: 1.0.1 + make-dir: 3.1.0 + pkg-dir: 4.2.0 + dev: true + /find-up/4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -2558,6 +2981,14 @@ packages: path-exists: 4.0.0 dev: true + /find-up/5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + /flat-cache/3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} @@ -2570,9 +3001,26 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true + /fp-ts/2.12.3: + resolution: {integrity: sha512-8m0XvW8kZbfnJOA4NvSVXu95mLbPf4LQGwQyqVukIYS4KzSNJiyKSmuZUmbVHteUi6MGkAJGPb0goPZqI+Tsqg==} + dev: true + /fraction.js/4.2.0: resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} + /fs-constants/1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + dev: true + + /fs-extra/10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.10 + jsonfile: 6.1.0 + universalify: 2.0.0 + dev: true + /fs-extra/9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -2583,6 +3031,12 @@ packages: universalify: 2.0.0 dev: true + /fs-jetpack/5.0.0: + resolution: {integrity: sha512-0f9QoIbfAq/DuafAQisvsHJmLnJB2D53d9FXIu0UZPUg4Kzocez1+AinToPON6JD/C60kDlye121puiR5ivfdg==} + dependencies: + minimatch: 5.1.0 + dev: true + /fs.realpath/1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} dev: true @@ -2685,6 +3139,13 @@ packages: path-is-absolute: 1.0.1 dev: true + /global-dirs/3.0.0: + resolution: {integrity: sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA==} + engines: {node: '>=10'} + dependencies: + ini: 2.0.0 + dev: true + /globals/11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} @@ -2745,21 +3206,63 @@ packages: has-symbols: 1.0.3 dev: true + /has-yarn/2.1.0: + resolution: {integrity: sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==} + engines: {node: '>=8'} + dev: true + /has/1.0.3: resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} engines: {node: '>= 0.4.0'} dependencies: function-bind: 1.1.1 + /hasha/5.2.2: + resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} + engines: {node: '>=8'} + dependencies: + is-stream: 2.0.1 + type-fest: 0.8.1 + dev: true + + /hosted-git-info/2.8.9: + resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} + dev: true + /html-escaper/2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} dev: true + /http-proxy-agent/5.0.0: + resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} + engines: {node: '>= 6'} + dependencies: + '@tootallnate/once': 2.0.0 + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + + /https-proxy-agent/5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: true + /human-signals/2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} dev: true + /ieee754/1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + dev: true + /ignore/4.0.6: resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} engines: {node: '>= 4'} @@ -2792,6 +3295,11 @@ packages: engines: {node: '>=0.8.19'} dev: true + /indent-string/4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + dev: true + /inflight/1.0.6: resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} dependencies: @@ -2803,6 +3311,11 @@ packages: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} dev: true + /ini/2.0.0: + resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} + engines: {node: '>=10'} + dev: true + /internal-slot/1.0.3: resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} engines: {node: '>= 0.4'} @@ -2857,6 +3370,12 @@ packages: has-tostringtag: 1.0.0 dev: true + /is-docker/2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + dev: true + /is-extglob/2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -2877,6 +3396,11 @@ packages: dependencies: is-extglob: 2.1.1 + /is-interactive/1.0.0: + resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} + engines: {node: '>=8'} + dev: true + /is-negative-zero/2.0.2: resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} engines: {node: '>= 0.4'} @@ -2893,6 +3417,16 @@ packages: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} + /is-path-cwd/2.2.0: + resolution: {integrity: sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==} + engines: {node: '>=6'} + dev: true + + /is-path-inside/3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + /is-regex/1.1.4: resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} engines: {node: '>= 0.4'} @@ -2926,12 +3460,33 @@ packages: has-symbols: 1.0.3 dev: true + /is-unicode-supported/0.1.0: + resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + engines: {node: '>=10'} + dev: true + /is-weakref/1.0.2: resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} dependencies: call-bind: 1.0.2 dev: true + /is-windows/1.0.2: + resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} + engines: {node: '>=0.10.0'} + dev: true + + /is-wsl/2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + dev: true + + /isarray/1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: true + /isexe/2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} dev: true @@ -3537,6 +4092,13 @@ packages: language-subtag-registry: 0.3.22 dev: true + /lazystream/1.0.1: + resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} + engines: {node: '>= 0.6.3'} + dependencies: + readable-stream: 2.3.7 + dev: true + /leven/3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} @@ -3565,6 +4127,29 @@ packages: p-locate: 4.1.0 dev: true + /locate-path/6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash.defaults/4.2.0: + resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==} + dev: true + + /lodash.difference/4.5.0: + resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==} + dev: true + + /lodash.flatten/4.4.0: + resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} + dev: true + + /lodash.isplainobject/4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: true + /lodash.memoize/4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} dev: true @@ -3577,10 +4162,22 @@ packages: resolution: {integrity: sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==} dev: true + /lodash.union/4.6.0: + resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==} + dev: true + /lodash/4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} dev: true + /log-symbols/4.1.0: + resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} + engines: {node: '>=10'} + dependencies: + chalk: 4.1.2 + is-unicode-supported: 0.1.0 + dev: true + /loose-envify/1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -3630,11 +4227,23 @@ packages: engines: {node: '>=6'} dev: true + /min-indent/1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + dev: true + /minimatch/3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 + /minimatch/5.1.0: + resolution: {integrity: sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==} + engines: {node: '>=10'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimist/1.2.6: resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} @@ -3646,6 +4255,10 @@ packages: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true + /ms/2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + /nanoid/3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -3655,6 +4268,11 @@ packages: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true + /new-github-issue-url/0.2.1: + resolution: {integrity: sha512-md4cGoxuT4T4d/HDOXbrUHkTKrp/vp+m3aOA7XXVYwNsUNMK49g3SQicTSeV5GIz/5QVGAeYRAOlyp9OvlgsYA==} + engines: {node: '>=10'} + dev: true + /next-auth/4.10.3_biqbaboplfbrettd7655fr4n2y: resolution: {integrity: sha512-7zc4aXYc/EEln7Pkcsn21V1IevaTZsMLJwapfbnKA4+JY0+jFzWbt5p/ljugesGIrN4VOZhpZIw50EaFZyghJQ==} engines: {node: ^12.19.0 || ^14.15.0 || ^16.13.0} @@ -3724,6 +4342,18 @@ packages: - babel-plugin-macros dev: false + /node-fetch/2.6.7: + resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: true + /node-int64/0.4.0: resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} dev: true @@ -3731,6 +4361,15 @@ packages: /node-releases/2.0.6: resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} + /normalize-package-data/2.5.0: + resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} + dependencies: + hosted-git-info: 2.8.9 + resolve: 1.22.1 + semver: 5.7.1 + validate-npm-package-license: 3.0.4 + dev: true + /normalize-path/3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -3835,6 +4474,14 @@ packages: mimic-fn: 2.1.0 dev: true + /open/7.4.2: + resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + is-wsl: 2.2.0 + dev: true + /openid-client/5.1.9: resolution: {integrity: sha512-o/11Xos2fRPpK1zQrPfSIhIusFrAkqGSPwkD0UlUB+CCuRzd7zrrBJwIjgnVv3VUSif9ZGXh2d3GSJNH2Koh5g==} engines: {node: ^12.19.0 || ^14.15.0 || ^16.13.0} @@ -3857,6 +4504,28 @@ packages: word-wrap: 1.2.3 dev: true + /ora/5.4.1: + resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} + engines: {node: '>=10'} + dependencies: + bl: 4.1.0 + chalk: 4.1.2 + cli-cursor: 3.1.0 + cli-spinners: 2.7.0 + is-interactive: 1.0.0 + is-unicode-supported: 0.1.0 + log-symbols: 4.1.0 + strip-ansi: 6.0.1 + wcwidth: 1.0.1 + dev: true + + /p-filter/2.1.0: + resolution: {integrity: sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw==} + engines: {node: '>=8'} + dependencies: + p-map: 2.1.0 + dev: true + /p-limit/2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} engines: {node: '>=6'} @@ -3878,6 +4547,33 @@ packages: p-limit: 2.3.0 dev: true + /p-locate/5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + + /p-map/2.1.0: + resolution: {integrity: sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==} + engines: {node: '>=6'} + dev: true + + /p-map/4.0.0: + resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} + engines: {node: '>=10'} + dependencies: + aggregate-error: 3.1.0 + dev: true + + /p-retry/4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + dev: true + /p-try/2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} engines: {node: '>=6'} @@ -4057,6 +4753,10 @@ packages: dependencies: '@prisma/engines': 4.3.1 + /process-nextick-args/2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + dev: true + /progress/2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'} @@ -4120,6 +4820,52 @@ packages: dependencies: pify: 2.3.0 + /read-pkg-up/7.0.1: + resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} + engines: {node: '>=8'} + dependencies: + find-up: 4.1.0 + read-pkg: 5.2.0 + type-fest: 0.8.1 + dev: true + + /read-pkg/5.2.0: + resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} + engines: {node: '>=8'} + dependencies: + '@types/normalize-package-data': 2.4.1 + normalize-package-data: 2.5.0 + parse-json: 5.2.0 + type-fest: 0.6.0 + dev: true + + /readable-stream/2.3.7: + resolution: {integrity: sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: true + + /readable-stream/3.6.0: + resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: true + + /readdir-glob/1.1.2: + resolution: {integrity: sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==} + dependencies: + minimatch: 5.1.0 + dev: true + /readdirp/3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -4146,6 +4892,11 @@ packages: engines: {node: '>=8'} dev: true + /replace-string/3.1.0: + resolution: {integrity: sha512-yPpxc4ZR2makceA9hy/jHNqc7QVkd4Je/N0WRHm6bs3PtivPuPynxE5ejU/mp5EhnCv8+uZL7vhz8rkluSlx+Q==} + engines: {node: '>=8'} + dev: true + /require-directory/2.1.1: resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} engines: {node: '>=0.10.0'} @@ -4195,6 +4946,19 @@ packages: supports-preserve-symlinks-flag: 1.0.0 dev: true + /restore-cursor/3.1.0: + resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} + engines: {node: '>=8'} + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + dev: true + + /retry/0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + dev: true + /reusify/1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} @@ -4221,6 +4985,10 @@ packages: resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} dev: true + /safe-buffer/5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: true + /safe-regex-test/1.0.0: resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} dependencies: @@ -4235,6 +5003,11 @@ packages: loose-envify: 1.4.0 dev: false + /semver/5.7.1: + resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true + dev: true + /semver/6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true @@ -4290,6 +5063,15 @@ packages: engines: {node: '>=8'} dev: true + /slice-ansi/3.0.0: + resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} + engines: {node: '>=8'} + dependencies: + ansi-styles: 4.3.0 + astral-regex: 2.0.0 + is-fullwidth-code-point: 3.0.0 + dev: true + /slice-ansi/4.0.0: resolution: {integrity: sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==} engines: {node: '>=10'} @@ -4319,6 +5101,28 @@ packages: resolution: {integrity: sha512-n98l9E2RMSJ9ON1AKisHzz7V42VDiBQGY6PB1BwRglz99wpVsSuGzQ+jOi6lFXBGVTCrRpltvjm+/XA+tpeJrg==} dev: true + /spdx-correct/3.1.1: + resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==} + dependencies: + spdx-expression-parse: 3.0.1 + spdx-license-ids: 3.0.12 + dev: true + + /spdx-exceptions/2.3.0: + resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==} + dev: true + + /spdx-expression-parse/3.0.1: + resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==} + dependencies: + spdx-exceptions: 2.3.0 + spdx-license-ids: 3.0.12 + dev: true + + /spdx-license-ids/3.0.12: + resolution: {integrity: sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==} + dev: true + /sprintf-js/1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} dev: true @@ -4376,6 +5180,18 @@ packages: es-abstract: 1.20.3 dev: true + /string_decoder/1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + dev: true + + /string_decoder/1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: true + /strip-ansi/6.0.1: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} @@ -4398,6 +5214,13 @@ packages: engines: {node: '>=6'} dev: true + /strip-indent/3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + dependencies: + min-indent: 1.0.1 + dev: true + /strip-json-comments/3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -4503,6 +5326,49 @@ packages: transitivePeerDependencies: - ts-node + /tar-stream/2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.0 + dev: true + + /temp-dir/1.0.0: + resolution: {integrity: sha512-xZFXEGbG7SNC3itwBzI3RYjq/cEhBkx2hJuKGIUOcEULmkQExXiHat2z/qkISYsuR+IKumhEfKKbV5qXmhICFQ==} + engines: {node: '>=4'} + dev: true + + /temp-dir/2.0.0: + resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} + engines: {node: '>=8'} + dev: true + + /temp-write/4.0.0: + resolution: {integrity: sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw==} + engines: {node: '>=8'} + dependencies: + graceful-fs: 4.2.10 + is-stream: 2.0.1 + make-dir: 3.1.0 + temp-dir: 1.0.0 + uuid: 3.4.0 + dev: true + + /tempy/1.0.1: + resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==} + engines: {node: '>=10'} + dependencies: + del: 6.1.1 + is-stream: 2.0.1 + temp-dir: 2.0.0 + type-fest: 0.16.0 + unique-string: 2.0.0 + dev: true + /terminal-link/2.1.1: resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==} engines: {node: '>=8'} @@ -4546,6 +5412,10 @@ packages: dependencies: is-number: 7.0.0 + /tr46/0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: true + /tree-kill/1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -4616,6 +5486,10 @@ packages: yn: 3.1.1 dev: true + /ts-pattern/4.0.5: + resolution: {integrity: sha512-Bq44KCEt7JVaNLa148mBCJkcQf4l7jtLEBDuDdeuLynWDA+1a60P4D0rMkqSM9mOKLQbIWUddE9h3XKyKwBeqA==} + dev: true + /tsconfig-paths/3.14.1: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} dependencies: @@ -4654,6 +5528,11 @@ packages: engines: {node: '>=4'} dev: true + /type-fest/0.16.0: + resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} + engines: {node: '>=10'} + dev: true + /type-fest/0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} engines: {node: '>=10'} @@ -4664,6 +5543,16 @@ packages: engines: {node: '>=10'} dev: true + /type-fest/0.6.0: + resolution: {integrity: sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==} + engines: {node: '>=8'} + dev: true + + /type-fest/0.8.1: + resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} + engines: {node: '>=8'} + dev: true + /typescript/4.8.3: resolution: {integrity: sha512-goMHfm00nWPa8UvR/CPSvykqf6dVV8x/dp0c5mFTMTIu0u0FlGWRioyy7Nn0PGAdHxpJZnuO/ut+PpQ8UiHAig==} engines: {node: '>=4.2.0'} @@ -4679,6 +5568,18 @@ packages: which-boxed-primitive: 1.0.2 dev: true + /undici/5.10.0: + resolution: {integrity: sha512-c8HsD3IbwmjjbLvoZuRI26TZic+TSEe8FPMLLOkN1AfYRhdjnKBU6yL+IwcSCbdZiX4e5t0lfMDLDCqj4Sq70g==} + engines: {node: '>=12.18'} + dev: true + + /unique-string/2.0.0: + resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==} + engines: {node: '>=8'} + dependencies: + crypto-random-string: 2.0.0 + dev: true + /universalify/2.0.0: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} @@ -4711,10 +5612,15 @@ packages: /util-deprecate/1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + /uuid/3.4.0: + resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} + deprecated: Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details. + hasBin: true + dev: true + /uuid/8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true - dev: false /uuid/9.0.0: resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} @@ -4738,6 +5644,13 @@ packages: convert-source-map: 1.8.0 dev: true + /validate-npm-package-license/3.0.4: + resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} + dependencies: + spdx-correct: 3.1.1 + spdx-expression-parse: 3.0.1 + dev: true + /vscode-jsonrpc/6.0.0: resolution: {integrity: sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==} engines: {node: '>=8.0.0 || >=10.0.0'} @@ -4783,6 +5696,23 @@ packages: makeerror: 1.0.12 dev: true + /wcwidth/1.0.1: + resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + dependencies: + defaults: 1.0.3 + dev: true + + /webidl-conversions/3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: true + + /whatwg-url/5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: true + /which-boxed-primitive/1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: @@ -4870,3 +5800,12 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true + + /zip-stream/4.1.0: + resolution: {integrity: sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==} + engines: {node: '>= 10'} + dependencies: + archiver-utils: 2.1.0 + compress-commons: 4.1.1 + readable-stream: 3.6.0 + dev: true diff --git a/samples/todo-target/.env b/samples/todo-target/.env new file mode 100644 index 000000000..23337add5 --- /dev/null +++ b/samples/todo-target/.env @@ -0,0 +1,5 @@ +NEXTAUTH_URL=http://localhost:3000 +GOOGLE_ID=423589857007-uioobc20f8ek0mend4g7qjck4c5a7f1s.apps.googleusercontent.com +GOOGLE_SECRET=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 +NEXTAUTH_SECRET=abc123 +DATABASE_URL="postgresql://postgres:abc123@localhost:5432/zenstack-todo?schema=public" diff --git a/samples/todo-target/.eslintrc.json b/samples/todo-target/.eslintrc.json new file mode 100644 index 000000000..758729586 --- /dev/null +++ b/samples/todo-target/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": ["next/core-web-vitals"] +} diff --git a/samples/todo-target/.gitignore b/samples/todo-target/.gitignore new file mode 100644 index 000000000..c87c9b392 --- /dev/null +++ b/samples/todo-target/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.pnpm-debug.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/samples/todo/.zenstack/.prisma/index-browser.js b/samples/todo-target/.zenstack/.prisma/index-browser.js similarity index 100% rename from samples/todo/.zenstack/.prisma/index-browser.js rename to samples/todo-target/.zenstack/.prisma/index-browser.js diff --git a/samples/todo/.zenstack/.prisma/index.d.ts b/samples/todo-target/.zenstack/.prisma/index.d.ts similarity index 100% rename from samples/todo/.zenstack/.prisma/index.d.ts rename to samples/todo-target/.zenstack/.prisma/index.d.ts diff --git a/samples/todo/.zenstack/.prisma/index.js b/samples/todo-target/.zenstack/.prisma/index.js similarity index 100% rename from samples/todo/.zenstack/.prisma/index.js rename to samples/todo-target/.zenstack/.prisma/index.js diff --git a/samples/todo/.zenstack/.prisma/libquery_engine-darwin-arm64.dylib.node b/samples/todo-target/.zenstack/.prisma/libquery_engine-darwin-arm64.dylib.node similarity index 100% rename from samples/todo/.zenstack/.prisma/libquery_engine-darwin-arm64.dylib.node rename to samples/todo-target/.zenstack/.prisma/libquery_engine-darwin-arm64.dylib.node diff --git a/samples/todo/.zenstack/.prisma/package.json b/samples/todo-target/.zenstack/.prisma/package.json similarity index 100% rename from samples/todo/.zenstack/.prisma/package.json rename to samples/todo-target/.zenstack/.prisma/package.json diff --git a/samples/todo/.zenstack/.prisma/runtime/edge.js b/samples/todo-target/.zenstack/.prisma/runtime/edge.js similarity index 100% rename from samples/todo/.zenstack/.prisma/runtime/edge.js rename to samples/todo-target/.zenstack/.prisma/runtime/edge.js diff --git a/samples/todo/.zenstack/.prisma/runtime/index-browser.d.ts b/samples/todo-target/.zenstack/.prisma/runtime/index-browser.d.ts similarity index 100% rename from samples/todo/.zenstack/.prisma/runtime/index-browser.d.ts rename to samples/todo-target/.zenstack/.prisma/runtime/index-browser.d.ts diff --git a/samples/todo/.zenstack/.prisma/runtime/index-browser.js b/samples/todo-target/.zenstack/.prisma/runtime/index-browser.js similarity index 100% rename from samples/todo/.zenstack/.prisma/runtime/index-browser.js rename to samples/todo-target/.zenstack/.prisma/runtime/index-browser.js diff --git a/samples/todo/.zenstack/.prisma/runtime/index.d.ts b/samples/todo-target/.zenstack/.prisma/runtime/index.d.ts similarity index 100% rename from samples/todo/.zenstack/.prisma/runtime/index.d.ts rename to samples/todo-target/.zenstack/.prisma/runtime/index.d.ts diff --git a/samples/todo/.zenstack/.prisma/runtime/index.js b/samples/todo-target/.zenstack/.prisma/runtime/index.js similarity index 100% rename from samples/todo/.zenstack/.prisma/runtime/index.js rename to samples/todo-target/.zenstack/.prisma/runtime/index.js diff --git a/samples/todo/.zenstack/.prisma/schema.prisma b/samples/todo-target/.zenstack/.prisma/schema.prisma similarity index 100% rename from samples/todo/.zenstack/.prisma/schema.prisma rename to samples/todo-target/.zenstack/.prisma/schema.prisma diff --git a/samples/todo/.zenstack/auth/authorize.ts b/samples/todo-target/.zenstack/auth/authorize.ts similarity index 100% rename from samples/todo/.zenstack/auth/authorize.ts rename to samples/todo-target/.zenstack/auth/authorize.ts diff --git a/samples/todo/.zenstack/auth/index.ts b/samples/todo-target/.zenstack/auth/index.ts similarity index 100% rename from samples/todo/.zenstack/auth/index.ts rename to samples/todo-target/.zenstack/auth/index.ts diff --git a/samples/todo/.zenstack/auth/next-auth-adapter.ts b/samples/todo-target/.zenstack/auth/next-auth-adapter.ts similarity index 100% rename from samples/todo/.zenstack/auth/next-auth-adapter.ts rename to samples/todo-target/.zenstack/auth/next-auth-adapter.ts diff --git a/samples/todo/.zenstack/client.ts b/samples/todo-target/.zenstack/client.ts similarity index 100% rename from samples/todo/.zenstack/client.ts rename to samples/todo-target/.zenstack/client.ts diff --git a/samples/todo/.zenstack/functions/index.ts b/samples/todo-target/.zenstack/functions/index.ts similarity index 100% rename from samples/todo/.zenstack/functions/index.ts rename to samples/todo-target/.zenstack/functions/index.ts diff --git a/samples/todo/.zenstack/functions/invite-user.ts b/samples/todo-target/.zenstack/functions/invite-user.ts similarity index 100% rename from samples/todo/.zenstack/functions/invite-user.ts rename to samples/todo-target/.zenstack/functions/invite-user.ts diff --git a/samples/todo/.zenstack/hooks/index.ts b/samples/todo-target/.zenstack/hooks/index.ts similarity index 100% rename from samples/todo/.zenstack/hooks/index.ts rename to samples/todo-target/.zenstack/hooks/index.ts diff --git a/samples/todo/.zenstack/hooks/request.ts b/samples/todo-target/.zenstack/hooks/request.ts similarity index 100% rename from samples/todo/.zenstack/hooks/request.ts rename to samples/todo-target/.zenstack/hooks/request.ts diff --git a/samples/todo/.zenstack/hooks/todo-list.ts b/samples/todo-target/.zenstack/hooks/todo-list.ts similarity index 100% rename from samples/todo/.zenstack/hooks/todo-list.ts rename to samples/todo-target/.zenstack/hooks/todo-list.ts diff --git a/samples/todo/.zenstack/hooks/todo.ts b/samples/todo-target/.zenstack/hooks/todo.ts similarity index 100% rename from samples/todo/.zenstack/hooks/todo.ts rename to samples/todo-target/.zenstack/hooks/todo.ts diff --git a/samples/todo/.zenstack/hooks/user.ts b/samples/todo-target/.zenstack/hooks/user.ts similarity index 100% rename from samples/todo/.zenstack/hooks/user.ts rename to samples/todo-target/.zenstack/hooks/user.ts diff --git a/samples/todo/.zenstack/index.ts b/samples/todo-target/.zenstack/index.ts similarity index 100% rename from samples/todo/.zenstack/index.ts rename to samples/todo-target/.zenstack/index.ts diff --git a/samples/todo/.zenstack/migrations/20220926071545_initial/migration.sql b/samples/todo-target/.zenstack/migrations/20220926071545_initial/migration.sql similarity index 100% rename from samples/todo/.zenstack/migrations/20220926071545_initial/migration.sql rename to samples/todo-target/.zenstack/migrations/20220926071545_initial/migration.sql diff --git a/samples/todo/.zenstack/migrations/migration_lock.toml b/samples/todo-target/.zenstack/migrations/migration_lock.toml similarity index 100% rename from samples/todo/.zenstack/migrations/migration_lock.toml rename to samples/todo-target/.zenstack/migrations/migration_lock.toml diff --git a/samples/todo/.zenstack/schema.prisma b/samples/todo-target/.zenstack/schema.prisma similarity index 100% rename from samples/todo/.zenstack/schema.prisma rename to samples/todo-target/.zenstack/schema.prisma diff --git a/samples/todo/.zenstack/server/data/index.ts b/samples/todo-target/.zenstack/server/data/index.ts similarity index 100% rename from samples/todo/.zenstack/server/data/index.ts rename to samples/todo-target/.zenstack/server/data/index.ts diff --git a/samples/todo/.zenstack/server/data/todo-list.ts b/samples/todo-target/.zenstack/server/data/todo-list.ts similarity index 100% rename from samples/todo/.zenstack/server/data/todo-list.ts rename to samples/todo-target/.zenstack/server/data/todo-list.ts diff --git a/samples/todo/.zenstack/server/data/utils.ts b/samples/todo-target/.zenstack/server/data/utils.ts similarity index 100% rename from samples/todo/.zenstack/server/data/utils.ts rename to samples/todo-target/.zenstack/server/data/utils.ts diff --git a/samples/todo/.zenstack/server/function/index.ts b/samples/todo-target/.zenstack/server/function/index.ts similarity index 100% rename from samples/todo/.zenstack/server/function/index.ts rename to samples/todo-target/.zenstack/server/function/index.ts diff --git a/samples/todo/.zenstack/server/function/invite-user.ts b/samples/todo-target/.zenstack/server/function/invite-user.ts similarity index 100% rename from samples/todo/.zenstack/server/function/invite-user.ts rename to samples/todo-target/.zenstack/server/function/invite-user.ts diff --git a/samples/todo/.zenstack/server/index.ts b/samples/todo-target/.zenstack/server/index.ts similarity index 100% rename from samples/todo/.zenstack/server/index.ts rename to samples/todo-target/.zenstack/server/index.ts diff --git a/samples/todo/.zenstack/types.ts b/samples/todo-target/.zenstack/types.ts similarity index 100% rename from samples/todo/.zenstack/types.ts rename to samples/todo-target/.zenstack/types.ts diff --git a/samples/todo-target/README.md b/samples/todo-target/README.md new file mode 100644 index 000000000..c87e0421d --- /dev/null +++ b/samples/todo-target/README.md @@ -0,0 +1,34 @@ +This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app). + +## Getting Started + +First, run the development server: + +```bash +npm run dev +# or +yarn dev +``` + +Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. + +You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file. + +[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`. + +The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages. + +## Learn More + +To learn more about Next.js, take a look at the following resources: + +- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. +- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. + +You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! + +## Deploy on Vercel + +The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. + +Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details. diff --git a/samples/todo-target/components/AccessDenied.tsx b/samples/todo-target/components/AccessDenied.tsx new file mode 100644 index 000000000..bb865f61c --- /dev/null +++ b/samples/todo-target/components/AccessDenied.tsx @@ -0,0 +1,20 @@ +import { signIn } from 'next-auth/react'; + +export default function AccessDenied() { + return ( + <> +

Access Denied

+

+ { + e.preventDefault(); + signIn(); + }} + > + You must be signed in to view this page + +

+ + ); +} diff --git a/samples/todo-target/components/LoginButton.tsx b/samples/todo-target/components/LoginButton.tsx new file mode 100644 index 000000000..f70de7283 --- /dev/null +++ b/samples/todo-target/components/LoginButton.tsx @@ -0,0 +1,22 @@ +import { useSession, signIn, signOut } from 'next-auth/react'; + +export default function Component() { + const { data: session } = useSession(); + if (session) { + return ( + <> +
Signed in as {session.user?.email}
+ + + ); + } + return ( + <> + + + ); +} diff --git a/samples/todo-target/functions/invite-user.ts b/samples/todo-target/functions/invite-user.ts new file mode 100644 index 000000000..7f4e79f14 --- /dev/null +++ b/samples/todo-target/functions/invite-user.ts @@ -0,0 +1,21 @@ +import { SpaceUserRole } from '@zenstack/.prisma'; +import { FunctionContext } from '@zenstack/types'; + +async function func( + context: FunctionContext, + spaceId: string, + userId: string, + role: SpaceUserRole +) { + const r = await context.db.spaceUser.create({ + data: { + userId, + spaceId, + role, + }, + }); + // send email + return r; +} + +export default func; diff --git a/samples/todo-target/next.config.js b/samples/todo-target/next.config.js new file mode 100644 index 000000000..ae887958d --- /dev/null +++ b/samples/todo-target/next.config.js @@ -0,0 +1,7 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = { + reactStrictMode: true, + swcMinify: true, +} + +module.exports = nextConfig diff --git a/samples/todo-target/package.json b/samples/todo-target/package.json new file mode 100644 index 000000000..0cc619fb8 --- /dev/null +++ b/samples/todo-target/package.json @@ -0,0 +1,37 @@ +{ + "name": "todo", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint", + "db-gen": "prisma generate --schema .zenstack/schema.prisma", + "db-push": "prisma db push --schema .zenstack/schema.prisma", + "db-migrate": "prisma migrate dev --schema .zenstack/schema.prisma", + "db-reset": "prisma migrate reset --schema .zenstack/schema.prisma" + }, + "dependencies": { + "@prisma/client": "^4.3.1", + "daisyui": "^2.31.0", + "next": "12.3.1", + "next-auth": "^4.10.3", + "react": "18.2.0", + "react-dom": "18.2.0", + "swr": "^1.3.0" + }, + "devDependencies": { + "@types/bcryptjs": "^2.4.2", + "@types/node": "^14.17.3", + "@types/react": "18.0.21", + "@types/react-dom": "18.0.6", + "autoprefixer": "^10.4.12", + "eslint": "^7.19.0", + "eslint-config-next": "12.3.1", + "postcss": "^8.4.16", + "prisma": "^4.3.1", + "tailwindcss": "^3.1.8", + "typescript": "^4.6.2" + } +} diff --git a/samples/todo-target/pages/_app.tsx b/samples/todo-target/pages/_app.tsx new file mode 100644 index 000000000..505acdf46 --- /dev/null +++ b/samples/todo-target/pages/_app.tsx @@ -0,0 +1,13 @@ +import '../styles/globals.css'; +import type { AppProps } from 'next/app'; +import { SessionProvider } from 'next-auth/react'; + +function MyApp({ Component, pageProps: { session, ...pageProps } }: AppProps) { + return ( + + + + ); +} + +export default MyApp; diff --git a/samples/todo-target/pages/api/auth/[...nextauth].ts b/samples/todo-target/pages/api/auth/[...nextauth].ts new file mode 100644 index 000000000..70334e68f --- /dev/null +++ b/samples/todo-target/pages/api/auth/[...nextauth].ts @@ -0,0 +1,51 @@ +import NextAuth, { NextAuthOptions } from 'next-auth'; +import CredentialsProvider from 'next-auth/providers/credentials'; +import GoogleProvider from 'next-auth/providers/google'; +import { Authorize, NextAuthAdapter as Adapter } from '@zenstack/auth'; +import { client } from '@zenstack'; + +export const authOptions: NextAuthOptions = { + // Configure one or more authentication providers + + adapter: Adapter(client), + + session: { + strategy: 'jwt', + }, + + providers: [ + GoogleProvider({ + clientId: process.env.GOOGLE_ID!, + clientSecret: process.env.GOOGLE_SECRET!, + }), + CredentialsProvider({ + credentials: { + email: { + label: 'Email Address', + type: 'email', + placeholder: 'john.doe@example.com', + }, + password: { + label: 'Password', + type: 'password', + placeholder: 'Your super secure password', + }, + }, + authorize: Authorize(client), + }), + ], + + callbacks: { + async session({ session, token }) { + return { + ...session, + user: { + ...session.user, + id: token.sub!, + }, + }; + }, + }, +}; + +export default NextAuth(authOptions); diff --git a/samples/todo-target/pages/api/hello.ts b/samples/todo-target/pages/api/hello.ts new file mode 100644 index 000000000..f8bcc7e5c --- /dev/null +++ b/samples/todo-target/pages/api/hello.ts @@ -0,0 +1,13 @@ +// Next.js API route support: https://nextjs.org/docs/api-routes/introduction +import type { NextApiRequest, NextApiResponse } from 'next' + +type Data = { + name: string +} + +export default function handler( + req: NextApiRequest, + res: NextApiResponse +) { + res.status(200).json({ name: 'John Doe' }) +} diff --git a/samples/todo-target/pages/api/zen/[...path].ts b/samples/todo-target/pages/api/zen/[...path].ts new file mode 100644 index 000000000..6930e427f --- /dev/null +++ b/samples/todo-target/pages/api/zen/[...path].ts @@ -0,0 +1,12 @@ +import { RequestHandler, RequestionHandlerOptions } from '@zenstack/server'; +import { NextApiRequest, NextApiResponse } from 'next'; +import { authOptions } from '@api/auth/[...nextauth]'; +import { unstable_getServerSession } from 'next-auth'; + +const options: RequestionHandlerOptions = { + async getServerUser(req: NextApiRequest, res: NextApiResponse) { + const session = await unstable_getServerSession(req, res, authOptions); + return session?.user; + }, +}; +export default RequestHandler(options); diff --git a/samples/todo-target/pages/index.tsx b/samples/todo-target/pages/index.tsx new file mode 100644 index 000000000..f8122b198 --- /dev/null +++ b/samples/todo-target/pages/index.tsx @@ -0,0 +1,106 @@ +import type { NextPage } from 'next'; +import LoginButton from '../components/LoginButton'; +import { useSession } from 'next-auth/react'; +import { useTodoList } from '@zenstack/hooks'; +import { inviteUser } from '@zenstack/functions'; +import { SpaceUserRole, TodoList } from '@zenstack/.prisma'; + +const Home: NextPage = () => { + const { data: session } = useSession(); + const { + create: createTodoList, + find: findTodoList, + del: deleteTodoList, + } = useTodoList(); + const { data: todoLists } = findTodoList(); + + async function onCreateTodoList() { + await createTodoList({ + data: { + title: 'My Todo List', + ownerId: session!.user.id, + spaceId: 'f0c9fc5c-e6e5-4146-a540-214f6ac5701c', + }, + }); + } + + async function onCreateFilledTodoList() { + await createTodoList({ + data: { + title: 'My Todo List', + ownerId: session!.user.id, + spaceId: 'f0c9fc5c-e6e5-4146-a540-214f6ac5701c', + todos: { + create: [ + { title: 'First Todo', ownerId: session!.user.id }, + ], + }, + }, + }); + } + + async function onDeleteTodoList(todoList: TodoList) { + await deleteTodoList(todoList.id); + } + + async function onInviteUser() { + await inviteUser( + 'f0c9fc5c-e6e5-4146-a540-214f6ac5701c', + 'dadd2e5b-d278-4695-8f6a-e6389bc109c0', + SpaceUserRole.ADMIN + ); + } + + function renderTodoLists() { + return ( + <> +
    + {todoLists?.map((todoList) => ( +
  • +

    {todoList.title}

    + +
  • + ))} +
+ + ); + } + + return ( +
+

Wonderful Todo

+
+ +
+ + {session && ( + <> + + + + + + +

Todo Lists

+ {renderTodoLists()} + + )} +
+ ); +}; + +export default Home; diff --git a/samples/todo-target/postcss.config.js b/samples/todo-target/postcss.config.js new file mode 100644 index 000000000..33ad091d2 --- /dev/null +++ b/samples/todo-target/postcss.config.js @@ -0,0 +1,6 @@ +module.exports = { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +} diff --git a/samples/todo-target/public/favicon.ico b/samples/todo-target/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 zcmeHv30#a{`}aL_*G&7qml|y<+KVaDM2m#dVr!KsA!#An?kSQM(q<_dDNCpjEux83 zLb9Z^XxbDl(w>%i@8hT6>)&Gu{h#Oeyszu?xtw#Zb1mO{pgX9699l+Qppw7jXaYf~-84xW z)w4x8?=youko|}Vr~(D$UXIbiXABHh`p1?nn8Po~fxRJv}|0e(BPs|G`(TT%kKVJAdg5*Z|x0leQq0 zkdUBvb#>9F()jo|T~kx@OM8$9wzs~t2l;K=woNssA3l6|sx2r3+kdfVW@e^8e*E}v zA1y5{bRi+3Z`uD3{F7LgFJDdvm;nJilkzDku>BwXH(8ItVCXk*-lSJnR?-2UN%hJ){&rlvg`CDTj z)Bzo!3v7Ou#83zEDEFcKt(f1E0~=rqeEbTnMvWR#{+9pg%7G8y>u1OVRUSoox-ovF z2Ydma(;=YuBY(eI|04{hXzZD6_f(v~H;C~y5=DhAC{MMS>2fm~1H_t2$56pc$NH8( z5bH|<)71dV-_oCHIrzrT`2s-5w_+2CM0$95I6X8p^r!gHp+j_gd;9O<1~CEQQGS8) zS9Qh3#p&JM-G8rHekNmKVewU;pJRcTAog68KYo^dRo}(M>36U4Us zfgYWSiHZL3;lpWT=zNAW>Dh#mB!_@Lg%$ms8N-;aPqMn+C2HqZgz&9~Eu z4|Kp<`$q)Uw1R?y(~S>ePdonHxpV1#eSP1B;Ogo+-Pk}6#0GsZZ5!||ev2MGdh}_m z{DeR7?0-1^zVs&`AV6Vt;r3`I`OI_wgs*w=eO%_#7Kepl{B@xiyCANc(l zzIyd4y|c6PXWq9-|KM8(zIk8LPk(>a)zyFWjhT!$HJ$qX1vo@d25W<fvZQ2zUz5WRc(UnFMKHwe1| zWmlB1qdbiA(C0jmnV<}GfbKtmcu^2*P^O?MBLZKt|As~ge8&AAO~2K@zbXelK|4T<{|y4`raF{=72kC2Kn(L4YyenWgrPiv z@^mr$t{#X5VuIMeL!7Ab6_kG$&#&5p*Z{+?5U|TZ`B!7llpVmp@skYz&n^8QfPJzL z0G6K_OJM9x+Wu2gfN45phANGt{7=C>i34CV{Xqlx(fWpeAoj^N0Biu`w+MVcCUyU* zDZuzO0>4Z6fbu^T_arWW5n!E45vX8N=bxTVeFoep_G#VmNlQzAI_KTIc{6>c+04vr zx@W}zE5JNSU>!THJ{J=cqjz+4{L4A{Ob9$ZJ*S1?Ggg3klFp!+Y1@K+pK1DqI|_gq z5ZDXVpge8-cs!o|;K73#YXZ3AShj50wBvuq3NTOZ`M&qtjj#GOFfgExjg8Gn8>Vq5 z`85n+9|!iLCZF5$HJ$Iu($dm?8~-ofu}tEc+-pyke=3!im#6pk_Wo8IA|fJwD&~~F zc16osQ)EBo58U7XDuMexaPRjU@h8tXe%S{fA0NH3vGJFhuyyO!Uyl2^&EOpX{9As0 zWj+P>{@}jxH)8|r;2HdupP!vie{sJ28b&bo!8`D^x}TE$%zXNb^X1p@0PJ86`dZyj z%ce7*{^oo+6%&~I!8hQy-vQ7E)0t0ybH4l%KltWOo~8cO`T=157JqL(oq_rC%ea&4 z2NcTJe-HgFjNg-gZ$6!Y`SMHrlj}Etf7?r!zQTPPSv}{so2e>Fjs1{gzk~LGeesX%r(Lh6rbhSo_n)@@G-FTQy93;l#E)hgP@d_SGvyCp0~o(Y;Ee8{ zdVUDbHm5`2taPUOY^MAGOw*>=s7=Gst=D+p+2yON!0%Hk` zz5mAhyT4lS*T3LS^WSxUy86q&GnoHxzQ6vm8)VS}_zuqG?+3td68_x;etQAdu@sc6 zQJ&5|4(I?~3d-QOAODHpZ=hlSg(lBZ!JZWCtHHSj`0Wh93-Uk)_S%zsJ~aD>{`A0~ z9{AG(e|q3g5B%wYKRxiL2Y$8(4w6bzchKuloQW#e&S3n+P- z8!ds-%f;TJ1>)v)##>gd{PdS2Oc3VaR`fr=`O8QIO(6(N!A?pr5C#6fc~Ge@N%Vvu zaoAX2&(a6eWy_q&UwOhU)|P3J0Qc%OdhzW=F4D|pt0E4osw;%<%Dn58hAWD^XnZD= z>9~H(3bmLtxpF?a7su6J7M*x1By7YSUbxGi)Ot0P77`}P3{)&5Un{KD?`-e?r21!4vTTnN(4Y6Lin?UkSM z`MXCTC1@4A4~mvz%Rh2&EwY))LeoT=*`tMoqcEXI>TZU9WTP#l?uFv+@Dn~b(>xh2 z;>B?;Tz2SR&KVb>vGiBSB`@U7VIWFSo=LDSb9F{GF^DbmWAfpms8Sx9OX4CnBJca3 zlj9(x!dIjN?OG1X4l*imJNvRCk}F%!?SOfiOq5y^mZW)jFL@a|r-@d#f7 z2gmU8L3IZq0ynIws=}~m^#@&C%J6QFo~Mo4V`>v7MI-_!EBMMtb%_M&kvAaN)@ZVw z+`toz&WG#HkWDjnZE!6nk{e-oFdL^$YnbOCN}JC&{$#$O27@|Tn-skXr)2ml2~O!5 zX+gYoxhoc7qoU?C^3~&!U?kRFtnSEecWuH0B0OvLodgUAi}8p1 zrO6RSXHH}DMc$&|?D004DiOVMHV8kXCP@7NKB zgaZq^^O<7PoKEp72kby@W0Z!Y*Ay{&vfg#C&gG@YVR9g?FEocMUi1gSN$+V+ayF45{a zuDZDTN}mS|;BO%gEf}pjBfN2-gIrU#G5~cucA;dokXW89%>AyXJJI z9X4UlIWA|ZYHgbI z5?oFk@A=Ik7lrEQPDH!H+b`7_Y~aDb_qa=B2^Y&Ow41cU=4WDd40dp5(QS-WMN-=Y z9g;6_-JdNU;|6cPwf$ak*aJIcwL@1n$#l~zi{c{EW?T;DaW*E8DYq?Umtz{nJ&w-M zEMyTDrC&9K$d|kZe2#ws6)L=7K+{ zQw{XnV6UC$6-rW0emqm8wJoeZK)wJIcV?dST}Z;G0Arq{dVDu0&4kd%N!3F1*;*pW zR&qUiFzK=@44#QGw7k1`3t_d8&*kBV->O##t|tonFc2YWrL7_eqg+=+k;!F-`^b8> z#KWCE8%u4k@EprxqiV$VmmtiWxDLgnGu$Vs<8rppV5EajBXL4nyyZM$SWVm!wnCj-B!Wjqj5-5dNXukI2$$|Bu3Lrw}z65Lc=1G z^-#WuQOj$hwNGG?*CM_TO8Bg-1+qc>J7k5c51U8g?ZU5n?HYor;~JIjoWH-G>AoUP ztrWWLbRNqIjW#RT*WqZgPJXU7C)VaW5}MiijYbABmzoru6EmQ*N8cVK7a3|aOB#O& zBl8JY2WKfmj;h#Q!pN%9o@VNLv{OUL?rixHwOZuvX7{IJ{(EdPpuVFoQqIOa7giLVkBOKL@^smUA!tZ1CKRK}#SSM)iQHk)*R~?M!qkCruaS!#oIL1c z?J;U~&FfH#*98^G?i}pA{ z9Jg36t4=%6mhY(quYq*vSxptes9qy|7xSlH?G=S@>u>Ebe;|LVhs~@+06N<4CViBk zUiY$thvX;>Tby6z9Y1edAMQaiH zm^r3v#$Q#2T=X>bsY#D%s!bhs^M9PMAcHbCc0FMHV{u-dwlL;a1eJ63v5U*?Q_8JO zT#50!RD619#j_Uf))0ooADz~*9&lN!bBDRUgE>Vud-i5ck%vT=r^yD*^?Mp@Q^v+V zG#-?gKlr}Eeqifb{|So?HM&g91P8|av8hQoCmQXkd?7wIJwb z_^v8bbg`SAn{I*4bH$u(RZ6*xUhuA~hc=8czK8SHEKTzSxgbwi~9(OqJB&gwb^l4+m`k*Q;_?>Y-APi1{k zAHQ)P)G)f|AyjSgcCFps)Fh6Bca*Xznq36!pV6Az&m{O8$wGFD? zY&O*3*J0;_EqM#jh6^gMQKpXV?#1?>$ml1xvh8nSN>-?H=V;nJIwB07YX$e6vLxH( zqYwQ>qxwR(i4f)DLd)-$P>T-no_c!LsN@)8`e;W@)-Hj0>nJ-}Kla4-ZdPJzI&Mce zv)V_j;(3ERN3_@I$N<^|4Lf`B;8n+bX@bHbcZTopEmDI*Jfl)-pFDvo6svPRoo@(x z);_{lY<;);XzT`dBFpRmGrr}z5u1=pC^S-{ce6iXQlLGcItwJ^mZx{m$&DA_oEZ)B{_bYPq-HA zcH8WGoBG(aBU_j)vEy+_71T34@4dmSg!|M8Vf92Zj6WH7Q7t#OHQqWgFE3ARt+%!T z?oLovLVlnf?2c7pTc)~cc^($_8nyKwsN`RA-23ed3sdj(ys%pjjM+9JrctL;dy8a( z@en&CQmnV(()bu|Y%G1-4a(6x{aLytn$T-;(&{QIJB9vMox11U-1HpD@d(QkaJdEb zG{)+6Dos_L+O3NpWo^=gR?evp|CqEG?L&Ut#D*KLaRFOgOEK(Kq1@!EGcTfo+%A&I z=dLbB+d$u{sh?u)xP{PF8L%;YPPW53+@{>5W=Jt#wQpN;0_HYdw1{ksf_XhO4#2F= zyPx6Lx2<92L-;L5PD`zn6zwIH`Jk($?Qw({erA$^bC;q33hv!d!>%wRhj# zal^hk+WGNg;rJtb-EB(?czvOM=H7dl=vblBwAv>}%1@{}mnpUznfq1cE^sgsL0*4I zJ##!*B?=vI_OEVis5o+_IwMIRrpQyT_Sq~ZU%oY7c5JMIADzpD!Upz9h@iWg_>>~j zOLS;wp^i$-E?4<_cp?RiS%Rd?i;f*mOz=~(&3lo<=@(nR!_Rqiprh@weZlL!t#NCc zO!QTcInq|%#>OVgobj{~ixEUec`E25zJ~*DofsQdzIa@5^nOXj2T;8O`l--(QyU^$t?TGY^7#&FQ+2SS3B#qK*k3`ye?8jUYSajE5iBbJls75CCc(m3dk{t?- zopcER9{Z?TC)mk~gpi^kbbu>b-+a{m#8-y2^p$ka4n60w;Sc2}HMf<8JUvhCL0B&Btk)T`ctE$*qNW8L$`7!r^9T+>=<=2qaq-;ll2{`{Rg zc5a0ZUI$oG&j-qVOuKa=*v4aY#IsoM+1|c4Z)<}lEDvy;5huB@1RJPquU2U*U-;gu z=En2m+qjBzR#DEJDO`WU)hdd{Vj%^0V*KoyZ|5lzV87&g_j~NCjwv0uQVqXOb*QrQ zy|Qn`hxx(58c70$E;L(X0uZZ72M1!6oeg)(cdKO ze0gDaTz+ohR-#d)NbAH4x{I(21yjwvBQfmpLu$)|m{XolbgF!pmsqJ#D}(ylp6uC> z{bqtcI#hT#HW=wl7>p!38sKsJ`r8}lt-q%Keqy%u(xk=yiIJiUw6|5IvkS+#?JTBl z8H5(Q?l#wzazujH!8o>1xtn8#_w+397*_cy8!pQGP%K(Ga3pAjsaTbbXJlQF_+m+-UpUUent@xM zg%jqLUExj~o^vQ3Gl*>wh=_gOr2*|U64_iXb+-111aH}$TjeajM+I20xw(((>fej-@CIz4S1pi$(#}P7`4({6QS2CaQS4NPENDp>sAqD z$bH4KGzXGffkJ7R>V>)>tC)uax{UsN*dbeNC*v}#8Y#OWYwL4t$ePR?VTyIs!wea+ z5Urmc)X|^`MG~*dS6pGSbU+gPJoq*^a=_>$n4|P^w$sMBBy@f*Z^Jg6?n5?oId6f{ z$LW4M|4m502z0t7g<#Bx%X;9<=)smFolV&(V^(7Cv2-sxbxopQ!)*#ZRhTBpx1)Fc zNm1T%bONzv6@#|dz(w02AH8OXe>kQ#1FMCzO}2J_mST)+ExmBr9cva-@?;wnmWMOk z{3_~EX_xadgJGv&H@zK_8{(x84`}+c?oSBX*Ge3VdfTt&F}yCpFP?CpW+BE^cWY0^ zb&uBN!Ja3UzYHK-CTyA5=L zEMW{l3Usky#ly=7px648W31UNV@K)&Ub&zP1c7%)`{);I4b0Q<)B}3;NMG2JH=X$U zfIW4)4n9ZM`-yRj67I)YSLDK)qfUJ_ij}a#aZN~9EXrh8eZY2&=uY%2N0UFF7<~%M zsB8=erOWZ>Ct_#^tHZ|*q`H;A)5;ycw*IcmVxi8_0Xk}aJA^ath+E;xg!x+As(M#0=)3!NJR6H&9+zd#iP(m0PIW8$ z1Y^VX`>jm`W!=WpF*{ioM?C9`yOR>@0q=u7o>BP-eSHqCgMDj!2anwH?s%i2p+Q7D zzszIf5XJpE)IG4;d_(La-xenmF(tgAxK`Y4sQ}BSJEPs6N_U2vI{8=0C_F?@7<(G; zo$~G=8p+076G;`}>{MQ>t>7cm=zGtfbdDXm6||jUU|?X?CaE?(<6bKDYKeHlz}DA8 zXT={X=yp_R;HfJ9h%?eWvQ!dRgz&Su*JfNt!Wu>|XfU&68iRikRrHRW|ZxzRR^`eIGt zIeiDgVS>IeExKVRWW8-=A=yA`}`)ZkWBrZD`hpWIxBGkh&f#ijr449~m`j6{4jiJ*C!oVA8ZC?$1RM#K(_b zL9TW)kN*Y4%^-qPpMP7d4)o?Nk#>aoYHT(*g)qmRUb?**F@pnNiy6Fv9rEiUqD(^O zzyS?nBrX63BTRYduaG(0VVG2yJRe%o&rVrLjbxTaAFTd8s;<<@Qs>u(<193R8>}2_ zuwp{7;H2a*X7_jryzriZXMg?bTuegABb^87@SsKkr2)0Gyiax8KQWstw^v#ix45EVrcEhr>!NMhprl$InQMzjSFH54x5k9qHc`@9uKQzvL4ihcq{^B zPrVR=o_ic%Y>6&rMN)hTZsI7I<3&`#(nl+3y3ys9A~&^=4?PL&nd8)`OfG#n zwAMN$1&>K++c{^|7<4P=2y(B{jJsQ0a#U;HTo4ZmWZYvI{+s;Td{Yzem%0*k#)vjpB zia;J&>}ICate44SFYY3vEelqStQWFihx%^vQ@Do(sOy7yR2@WNv7Y9I^yL=nZr3mb zXKV5t@=?-Sk|b{XMhA7ZGB@2hqsx}4xwCW!in#C zI@}scZlr3-NFJ@NFaJlhyfcw{k^vvtGl`N9xSo**rDW4S}i zM9{fMPWo%4wYDG~BZ18BD+}h|GQKc-g^{++3MY>}W_uq7jGHx{mwE9fZiPCoxN$+7 zrODGGJrOkcPQUB(FD5aoS4g~7#6NR^ma7-!>mHuJfY5kTe6PpNNKC9GGRiu^L31uG z$7v`*JknQHsYB!Tm_W{a32TM099djW%5e+j0Ve_ct}IM>XLF1Ap+YvcrLV=|CKo6S zb+9Nl3_YdKP6%Cxy@6TxZ>;4&nTneadr z_ES90ydCev)LV!dN=#(*f}|ZORFdvkYBni^aLbUk>BajeWIOcmHP#8S)*2U~QKI%S zyrLmtPqb&TphJ;>yAxri#;{uyk`JJqODDw%(Z=2`1uc}br^V%>j!gS)D*q*f_-qf8&D;W1dJgQMlaH5er zN2U<%Smb7==vE}dDI8K7cKz!vs^73o9f>2sgiTzWcwY|BMYHH5%Vn7#kiw&eItCqa zIkR2~Q}>X=Ar8W|^Ms41Fm8o6IB2_j60eOeBB1Br!boW7JnoeX6Gs)?7rW0^5psc- zjS16yb>dFn>KPOF;imD}e!enuIniFzv}n$m2#gCCv4jM#ArwlzZ$7@9&XkFxZ4n!V zj3dyiwW4Ki2QG{@i>yuZXQizw_OkZI^-3otXC{!(lUpJF33gI60ak;Uqitp74|B6I zgg{b=Iz}WkhCGj1M=hu4#Aw173YxIVbISaoc z-nLZC*6Tgivd5V`K%GxhBsp@SUU60-rfc$=wb>zdJzXS&-5(NRRodFk;Kxk!S(O(a0e7oY=E( zAyS;Ow?6Q&XA+cnkCb{28_1N8H#?J!*$MmIwLq^*T_9-z^&UE@A(z9oGYtFy6EZef LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/samples/todo-target/public/vercel.svg b/samples/todo-target/public/vercel.svg new file mode 100644 index 000000000..fbf0e25a6 --- /dev/null +++ b/samples/todo-target/public/vercel.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/samples/todo-target/schema.zmodel b/samples/todo-target/schema.zmodel new file mode 100644 index 000000000..5ef0c0dc9 --- /dev/null +++ b/samples/todo-target/schema.zmodel @@ -0,0 +1,118 @@ +/* +* A sample model for a collaborative Todo app +*/ + +// Datasource +datasource db { + provider = 'postgresql' + url = env('DATABASE_URL') +} + +enum SpaceUserRole { + USER + ADMIN +} + +model Space { + id String @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + name String @length(1, 100) + slug String @unique @length(1, 20) + members SpaceUser[] + todoList TodoList[] + + // require login + @@deny('all', auth() == null) + // everyone can create a space + @@allow('create', true) + + // any user in the space can read the space + @@allow('read', members?[user == auth()]) + + // space admin can update and delete + @@allow('update,delete', members?[user == auth() && role == ADMIN]) +} + +model SpaceUser { + id String @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + space Space @relation(fields:[spaceId], references: [id], onDelete: Cascade) + spaceId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId String + role SpaceUserRole + + @@unique([userId, spaceId]) + + // require login + @@deny('all', auth() == null) + + // space admin can create/update/delete + @@allow('create,update,delete', space.members?[user == auth() && role == ADMIN]) + + // user can read entries for spaces which he's a member of + @@allow('read', space.members?[user == auth()]) +} + +model User { + id String @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + email String @unique @email + name String? @length(1, 100) + spaces SpaceUser[] + image String? @url + todoLists TodoList[] + todos Todo[] + + // can be created by anyone, even not logged in + @@allow('create', true) + + // can be read by users sharing any space + @@allow('read', spaces?[auth() == user]) + + // can only be updated and deleted by himeself + @@allow('update,delete', auth() == this) +} + +model TodoList { + id String @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade) + spaceId String + owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) + ownerId String + title String @length(1, 20) + private Boolean @default(false) + todos Todo[] + + // require login + @@deny('all', auth() == null) + + // can be read by owner or space members (only if not private) + @@allow('read', owner == auth() || (space.members?[user == auth()] && !private)) + + // can be created/updated/deleted by owner + @@allow('create,update,delete', owner == auth() && space.members?[user == auth()]) +} + +model Todo { + id String @id + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt + owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) + ownerId String + todoList TodoList @relation(fields: [todoListId], references: [id], onDelete: Cascade) + todoListId String + title String + completedAt DateTime? + + // require login + @@deny('all', auth() == null) + + // owner has full access, also space members have full access (if the parent TodoList is not private) + @@allow('all', todoList.owner == auth() || (todoList.space.members?[user == auth()] && !todoList.private)) +} diff --git a/samples/todo-target/styles/globals.css b/samples/todo-target/styles/globals.css new file mode 100644 index 000000000..b5c61c956 --- /dev/null +++ b/samples/todo-target/styles/globals.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/samples/todo-target/tailwind.config.js b/samples/todo-target/tailwind.config.js new file mode 100644 index 000000000..89705bc79 --- /dev/null +++ b/samples/todo-target/tailwind.config.js @@ -0,0 +1,11 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + './pages/**/*.{js,ts,jsx,tsx}', + './components/**/*.{js,ts,jsx,tsx}', + ], + theme: { + extend: {}, + }, + plugins: [require('daisyui')], +}; diff --git a/samples/todo-target/tsconfig.json b/samples/todo-target/tsconfig.json new file mode 100644 index 000000000..854c3c712 --- /dev/null +++ b/samples/todo-target/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "es5", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "node", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "preserve", + "incremental": true, + "baseUrl": ".", + "paths": { + "@api/*": ["pages/api/*"], + "@lib/*": ["lib/*"], + "@components/*": ["lib/components/*"], + "@components": ["lib/components/index"], + "@zenstack/*": [".zenstack/*"], + "@zenstack": [".zenstack/index"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} diff --git a/samples/todo-target/types/next-auth.d.ts b/samples/todo-target/types/next-auth.d.ts new file mode 100644 index 000000000..3fdf4e165 --- /dev/null +++ b/samples/todo-target/types/next-auth.d.ts @@ -0,0 +1,14 @@ +import { Session } from 'next-auth'; +import { JWT } from 'next-auth/jwt'; + +/** Example on how to extend the built-in session types */ +declare module 'next-auth' { + interface Session { + user: { id: string; name: string; email: string }; + } +} + +/** Example on how to extend the built-in types for JWT */ +declare module 'next-auth/jwt' { + interface JWT {} +} diff --git a/samples/todo-target/types/next.d.ts b/samples/todo-target/types/next.d.ts new file mode 100644 index 000000000..777c0a0be --- /dev/null +++ b/samples/todo-target/types/next.d.ts @@ -0,0 +1,16 @@ +import type { NextComponentType, NextPageContext } from 'next'; +import type { Session } from 'next-auth'; +import type { Router } from 'next/router'; + +declare module 'next/app' { + type AppProps

> = { + Component: NextComponentType; + router: Router; + __N_SSG?: boolean; + __N_SSP?: boolean; + pageProps: P & { + /** Initial session passed in from `getServerSideProps` or `getInitialProps` */ + session?: Session; + }; + }; +} diff --git a/samples/todo/.gitignore b/samples/todo/.gitignore index c87c9b392..bc7bca6f0 100644 --- a/samples/todo/.gitignore +++ b/samples/todo/.gitignore @@ -34,3 +34,5 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +/.zenstack diff --git a/samples/todo/schema.zmodel b/samples/todo/schema.zmodel index b004eb066..778b77842 100644 --- a/samples/todo/schema.zmodel +++ b/samples/todo/schema.zmodel @@ -14,15 +14,15 @@ enum SpaceUserRole { model Space { id String @id - createdAt DateTime @createdAt + createdAt DateTime @default(now()) updatedAt DateTime @updatedAt name String @length(1, 100) slug String @unique @length(1, 20) members SpaceUser[] + todoLists TodoList[] // require login - @@deny('all', auth() == null) - + @@deny('all', auth() == null) // everyone can create a space @@allow('create', true) @@ -35,14 +35,15 @@ model Space { model SpaceUser { id String @id - createdAt DateTime @createdAt + createdAt DateTime @default(now()) updatedAt DateTime @updatedAt - space Space @cascade - user User @cascade + space Space @relation(fields:[spaceId], references: [id], onDelete: Cascade) + spaceId String + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + userId String role SpaceUserRole - todoLists TodoList[] - @@unique([user, space]) + @@unique([userId, spaceId]) // require login @@deny('all', auth() == null) @@ -56,13 +57,14 @@ model SpaceUser { model User { id String @id - createdAt DateTime @createdAt + createdAt DateTime @default(now()) updatedAt DateTime @updatedAt email String @unique @email name String? @length(1, 100) spaces SpaceUser[] image String? @url todoLists TodoList[] + todos Todo[] // can be created by anyone, even not logged in @@allow('create', true) @@ -76,10 +78,12 @@ model User { model TodoList { id String @id - createdAt DateTime @createdAt + createdAt DateTime @default(now()) updatedAt DateTime @updatedAt - space Space @cascade - owner User + space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade) + spaceId String + owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) + ownerId String title String @length(1, 20) private Boolean @default(false) todos Todo[] @@ -96,10 +100,12 @@ model TodoList { model Todo { id String @id - createdAt DateTime @createdAt + createdAt DateTime @default(now()) updatedAt DateTime @updatedAt - owner User - todoList TodoList @cascade + owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) + ownerId String + todoList TodoList @relation(fields: [todoListId], references: [id], onDelete: Cascade) + todoListId String title String completedAt DateTime? From ac7364b29d721fbb7a8b9530111f226808058260 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Wed, 5 Oct 2022 21:32:59 +0800 Subject: [PATCH 03/15] update --- .vscode/launch.json | 2 +- packages/runtime/package.json | 14 +- packages/runtime/src/index.ts | 1 + packages/runtime/src/request.ts | 75 + packages/runtime/tsconfig.json | 2 +- packages/schema/package.json | 6 +- packages/schema/src/cli/cli-util.ts | 2 +- packages/schema/src/cli/generator.ts | 24 - packages/schema/src/cli/index.ts | 28 +- .../schema/src/generator/next-auth/index.ts | 183 + packages/schema/src/generator/prisma/index.ts | 23 +- .../schema/src/generator/react-hooks/index.ts | 278 + .../schema/src/generator/service/index.ts | 43 + .../schema/src/language-server/stdlib.zmodel | 2 + pnpm-lock.yaml | 259 +- samples/todo-target/.zenstack/client.ts | 19 +- .../todo-target/.zenstack/hooks/todo-list.ts | 78 +- samples/todo/functions/invite-user.ts | 21 - samples/todo/package-lock.json | 6804 +++++++++++++++++ samples/todo/package.json | 8 +- samples/todo/pages/api/auth/[...nextauth].ts | 8 +- samples/todo/schema.zmodel | 48 +- 22 files changed, 7752 insertions(+), 176 deletions(-) create mode 100644 packages/runtime/src/request.ts delete mode 100644 packages/schema/src/cli/generator.ts create mode 100644 packages/schema/src/generator/next-auth/index.ts create mode 100644 packages/schema/src/generator/react-hooks/index.ts create mode 100644 packages/schema/src/generator/service/index.ts delete mode 100644 samples/todo/functions/invite-user.ts create mode 100644 samples/todo/package-lock.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 2ae775061..18b3d7fa7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -8,7 +8,7 @@ { "name": "Generate for Todo Sample", "program": "${workspaceFolder}/packages/schema/bin/cli", - "cwd": "${workspaceFolder}/packages/schema", + "cwd": "${workspaceFolder}/samples/todo/", "args": [ "generate", "${workspaceFolder}/samples/todo/schema.zmodel", diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 95cf323dc..098a400e9 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,12 +1,12 @@ { "name": "@zenstackhq/runtime", - "version": "0.1.0", - "description": "", + "version": "0.1.1", + "description": "ZenStack runtime library", "main": "lib/index.js", "types": "lib/index.d.ts", "scripts": { "build": "tsc", - "test": "echo \"Error: no test specified\" && exit 1" + "npm-publish": "pnpm build && pnpm publish --no-git-checks --access public" }, "keywords": [], "author": "", @@ -15,17 +15,13 @@ "lib/**/*" ], "dependencies": { - "@next-auth/prisma-adapter": "^1.0.4", - "bcryptjs": "^2.4.3", - "next-auth": "^4.10.3" + "swr": "^1.3.0" }, "peerDependencies": { "react": "^17.0.2 || ^18", - "react-dom": "^17.0.2 || ^18", - "@prisma/client": "^4.3.1" + "react-dom": "^17.0.2 || ^18" }, "devDependencies": { - "@types/bcryptjs": "^2.4.2", "typescript": "^4.6.2" } } diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index e69de29bb..56e4b0555 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -0,0 +1 @@ +export * from './request'; diff --git a/packages/runtime/src/request.ts b/packages/runtime/src/request.ts new file mode 100644 index 000000000..b62269e7b --- /dev/null +++ b/packages/runtime/src/request.ts @@ -0,0 +1,75 @@ +import useSWR, { useSWRConfig } from 'swr'; +import type { ScopedMutator } from 'swr/dist/types'; + +const fetcher = async (url: string, options?: RequestInit) => { + const res = await fetch(url, options); + if (!res.ok) { + const error: Error & { info?: any; status?: number } = new Error( + 'An error occurred while fetching the data.' + ); + error.info = await res.json(); + error.status = res.status; + throw error; + } + return res.json(); +}; + +function makeUrl(url: string, args: unknown) { + return args ? url + `q=${encodeURIComponent(JSON.stringify(args))}` : url; +} + +export function get(url: string, args?: unknown) { + return useSWR(makeUrl(url, args), fetcher); +} + +export async function post( + url: string, + data: Data, + mutate: ScopedMutator +) { + const r: Result = await fetcher(url, { + method: 'POST', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify(data), + }); + mutate(url); + return r; +} + +export async function put( + url: string, + data: Data, + mutate: ScopedMutator +) { + const r: Result = await fetcher(url, { + method: 'PUT', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify(data), + }); + mutate(url, r); + return r; +} + +export async function del( + url: string, + args: unknown, + mutate: ScopedMutator +) { + const reqUrl = makeUrl(url, args); + const r: Result = await fetcher(reqUrl, { + method: 'DELETE', + }); + const path = url.split('/'); + path.pop(); + mutate(path.join('/')); + return r; +} + +export function getMutate() { + const { mutate } = useSWRConfig(); + return mutate; +} diff --git a/packages/runtime/tsconfig.json b/packages/runtime/tsconfig.json index 1833391f0..0cb440399 100644 --- a/packages/runtime/tsconfig.json +++ b/packages/runtime/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "target": "ES6", "module": "ESNext", - "lib": ["ESNext"], + "lib": ["ESNext", "DOM"], "sourceMap": true, "outDir": "./lib", "strict": true, diff --git a/packages/schema/package.json b/packages/schema/package.json index 51ce8f57c..a1433e0e3 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -49,7 +49,7 @@ "main": "./out/extension.js", "scripts": { "vscode:prepublish": "npm run build && npm run lint", - "build": "tsc -b tsconfig.json", + "build": "tsc -b tsconfig.json && cp src/language-server/stdlib.zmodel ./out/language-server/", "ts:watch": "tsc -b tsconfig.json --watch", "lint": "eslint src --ext ts", "langium:generate": "langium generate", @@ -58,11 +58,13 @@ "test": "jest" }, "dependencies": { + "change-case": "^4.1.2", "chevrotain": "^9.1.0", "colors": "^1.4.0", "commander": "^8.0.0", "langium": "^0.4.0", - "uuid": "^9.0.0", + "promisify": "^0.0.3", + "ts-morph": "^16.0.0", "vscode-jsonrpc": "^8.0.2", "vscode-languageclient": "^7.0.0", "vscode-languageserver": "^7.0.0", diff --git a/packages/schema/src/cli/cli-util.ts b/packages/schema/src/cli/cli-util.ts index 93e7cdb1c..8552ae0a7 100644 --- a/packages/schema/src/cli/cli-util.ts +++ b/packages/schema/src/cli/cli-util.ts @@ -25,7 +25,7 @@ export async function extractDocument( const stdLib = services.shared.workspace.LangiumDocuments.getOrCreateDocument( - URI.file(path.resolve('src/language-server/stdlib.zmodel')) + URI.file(path.join(__dirname, '../language-server/stdlib.zmodel')) ); const document = services.shared.workspace.LangiumDocuments.getOrCreateDocument( diff --git a/packages/schema/src/cli/generator.ts b/packages/schema/src/cli/generator.ts deleted file mode 100644 index d6cf4f649..000000000 --- a/packages/schema/src/cli/generator.ts +++ /dev/null @@ -1,24 +0,0 @@ -import fs from 'fs'; -import { CompositeGeneratorNode, NL, processGeneratorNode } from 'langium'; -import path from 'path'; -import { Model } from '../language-server/generated/ast'; -import { extractDestinationAndName } from './cli-util'; - -export function generateJavaScript( - model: Model, - filePath: string, - destination: string | undefined -): string { - const data = extractDestinationAndName(filePath, destination); - const generatedFilePath = `${path.join(data.destination, data.name)}.js`; - - const fileNode = new CompositeGeneratorNode(); - fileNode.append('"use strict";', NL, NL); - // model.greetings.forEach(greeting => fileNode.append(`console.log('Hello, ${greeting.person.ref?.name}!');`, NL)); - - if (!fs.existsSync(data.destination)) { - fs.mkdirSync(data.destination, { recursive: true }); - } - fs.writeFileSync(generatedFilePath, processGeneratorNode(fileNode)); - return generatedFilePath; -} diff --git a/packages/schema/src/cli/index.ts b/packages/schema/src/cli/index.ts index cafd72991..c6c3a5c87 100644 --- a/packages/schema/src/cli/index.ts +++ b/packages/schema/src/cli/index.ts @@ -3,8 +3,14 @@ import { Model } from '../language-server/generated/ast'; import { ZModelLanguageMetaData } from '../language-server/generated/module'; import { createZModelServices } from '../language-server/zmodel-module'; import { extractAstNode } from './cli-util'; -import PrismaGenerator from '../generator/prisma'; import { Context } from '../generator/types'; +import * as path from 'path'; +import * as fs from 'fs'; +import colors from 'colors'; +import PrismaGenerator from '../generator/prisma'; +import ServiceGenerator from '../generator/service'; +import ReactHooksGenerator from '../generator/react-hooks'; +import NextAuthGenerator from '../generator/next-auth'; export const generateAction = async ( fileName: string, @@ -13,15 +19,31 @@ export const generateAction = async ( const services = createZModelServices().ZModel; const model = await extractAstNode(fileName, services); - const generators = [new PrismaGenerator()]; const context: Context = { schema: model, - outDir: opts.destination, + outDir: path.resolve(opts.destination), }; + if (!fs.existsSync(context.outDir)) { + fs.mkdirSync(context.outDir); + } + + console.log(colors.bold('⌛️ Running ZenStack generators')); + + const generators = [ + new PrismaGenerator(), + new ServiceGenerator(), + new ReactHooksGenerator(), + new NextAuthGenerator(), + ]; + for (const generator of generators) { await generator.generate(context); } + + console.log( + colors.green(colors.bold('👻 All generators completed successfully!')) + ); }; export type GenerateOptions = { diff --git a/packages/schema/src/generator/next-auth/index.ts b/packages/schema/src/generator/next-auth/index.ts new file mode 100644 index 000000000..f8188709f --- /dev/null +++ b/packages/schema/src/generator/next-auth/index.ts @@ -0,0 +1,183 @@ +import { Context, Generator } from '../types'; +import { Project } from 'ts-morph'; +import * as path from 'path'; + +export default class NextAuthGenerator implements Generator { + async generate(context: Context) { + const project = new Project(); + + this.generateIndex(project, context); + this.generateAdapter(project, context); + this.generateAuthorize(project, context); + + await project.save(); + } + + generateIndex(project: Project, context: Context) { + const sf = project.createSourceFile( + path.join(context.outDir, 'auth/index.ts'), + undefined, + { overwrite: true } + ); + + sf.addStatements([ + `export * from './next-auth-adapter';`, + `export * from './authorize';`, + ]); + + sf.formatText(); + } + + generateAdapter(project: Project, context: Context) { + const content = ` + import { ZenStackService } from '../service'; + import { Adapter } from 'next-auth/adapters'; + import { Prisma } from '@zenstack/.prisma'; + + export function NextAuthAdapter(service: ZenStackService): Adapter { + const p = service.prisma; + return { + createUser: (data) => p.user.create({ data: data as Prisma.UserCreateInput }), + getUser: (id) => p.user.findUnique({ where: { id } }), + getUserByEmail: (email) => p.user.findUnique({ where: { email } }), + async getUserByAccount(provider_providerAccountId) { + const account = await p.account.findUnique({ + where: { provider_providerAccountId }, + select: { user: true }, + }); + return account?.user ?? null; + }, + updateUser: (data) => p.user.update({ where: { id: data.id }, data: data as Prisma.UserUpdateInput }), + deleteUser: (id) => p.user.delete({ where: { id } }), + linkAccount: (data) => p.account.create({ data }) as any, + unlinkAccount: (provider_providerAccountId) => + p.account.delete({ where: { provider_providerAccountId } }) as any, + async getSessionAndUser(sessionToken) { + const userAndSession = await p.session.findUnique({ + where: { sessionToken }, + include: { user: true }, + }); + if (!userAndSession) return null; + const { user, ...session } = userAndSession; + return { user, session }; + }, + createSession: (data) => p.session.create({ data }), + updateSession: (data) => + p.session.update({ + data, + where: { sessionToken: data.sessionToken }, + }), + deleteSession: (sessionToken) => + p.session.delete({ where: { sessionToken } }), + createVerificationToken: (data) => p.verificationToken.create({ data }), + async useVerificationToken(identifier_token) { + try { + return await p.verificationToken.delete({ + where: { identifier_token }, + }); + } catch (error) { + // If token already used/deleted, just return null + // https://www.prisma.io/docs/reference/api-reference/error-reference#p2025 + if ( + (error as Prisma.PrismaClientKnownRequestError).code === + 'P2025' + ) + return null; + throw error; + } + }, + }; + } + `; + + const sf = project.createSourceFile( + path.join(context.outDir, 'auth/next-auth-adapter.ts'), + content, + { overwrite: true } + ); + + sf.formatText(); + } + + generateAuthorize(project: Project, context: Context) { + const content = ` + import { ZenStackService } from '../service'; + import { hash, compare } from 'bcryptjs'; + + async function hashPassword(password: string) { + const hashedPassword = await hash(password, 12); + return hashedPassword; + } + + async function verifyPassword(password: string, hashedPassword: string) { + const isValid = await compare(password, hashedPassword); + return isValid; + } + + export function authorize(service: ZenStackService) { + return async ( + credentials: Record<'email' | 'password', string> | undefined + ) => { + try { + let maybeUser = await service.prisma.user.findFirst({ + where: { + email: credentials!.email, + }, + select: { + id: true, + email: true, + password: true, + name: true, + }, + }); + + if (!maybeUser) { + if (!credentials!.password || !credentials!.email) { + throw new Error('Invalid Credentials'); + } + + maybeUser = await service.prisma.user.create({ + data: { + email: credentials!.email, + password: await hashPassword(credentials!.password), + }, + select: { + id: true, + email: true, + password: true, + name: true, + }, + }); + } else { + const isValid = await verifyPassword( + credentials!.password, + maybeUser.password + ); + + if (!isValid) { + throw new Error('Invalid Credentials'); + } + } + + return { + id: maybeUser.id, + email: maybeUser.email, + name: maybeUser.name, + }; + } catch (error) { + console.log(error); + throw error; + } + }; + } + `; + + const sf = project.createSourceFile( + path.join(context.outDir, 'auth/authorize.ts'), + content, + { overwrite: true } + ); + + sf.formatText(); + } +} diff --git a/packages/schema/src/generator/prisma/index.ts b/packages/schema/src/generator/prisma/index.ts index dceb4ba50..32dee8d4a 100644 --- a/packages/schema/src/generator/prisma/index.ts +++ b/packages/schema/src/generator/prisma/index.ts @@ -33,6 +33,7 @@ import { PrismaModel, ModelFieldType, } from './prisma-builder'; +import { execSync } from 'child_process'; const supportedProviders = ['postgresql', 'mysql', 'sqlite', 'sqlserver']; const supportedAttrbutes = [ @@ -72,12 +73,24 @@ export default class PrismaGenerator implements Generator { this.generateGenerator(context, prisma); - await writeFile( - path.join(context.outDir, 'schema.prisma'), - prisma.toString() - ); + const outFile = path.join(context.outDir, 'schema.prisma'); + await writeFile(outFile, prisma.toString()); + console.log(colors.blue(`Prisma schema generated`)); + + // run prisma generate and install @prisma/client + await this.generatePrismaClient(outFile); + } + + async generatePrismaClient(schemaFile: string) { + try { + execSync('npx prisma'); + } catch (err) { + execSync(`npm i prisma @prisma/client`); + console.log(colors.blue('Prisma package installed')); + } - console.log(colors.green('Prisma schema generated successfully')); + execSync(`npx prisma generate --schema "${schemaFile}"`); + console.log(colors.blue('Prisma client generated')); } private isStringLiteral(node: AstNode): node is LiteralExpr { diff --git a/packages/schema/src/generator/react-hooks/index.ts b/packages/schema/src/generator/react-hooks/index.ts new file mode 100644 index 000000000..38e2a0371 --- /dev/null +++ b/packages/schema/src/generator/react-hooks/index.ts @@ -0,0 +1,278 @@ +import { Context, Generator } from '../types'; +import { Project } from 'ts-morph'; +import * as path from 'path'; +import { camelCase, paramCase } from 'change-case'; +import { DataModel, isDataModel } from '../../language-server/generated/ast'; +import colors from 'colors'; + +export default class ReactHooksGenerator implements Generator { + async generate(context: Context) { + const project = new Project(); + + const models = context.schema.declarations.filter( + (d) => + isDataModel(d) && + // only generate hooks if model has at least one @@allow rule + this.hasAllowRules(d) + ) as DataModel[]; + + this.generateIndex(project, context, models); + this.generateRequestRuntime(project, context); + + models.forEach((d) => this.generateModelHooks(project, context, d)); + + await project.save(); + + console.log(colors.blue('React hooks generated')); + } + + private hasAllowRules(model: DataModel) { + return !!model.attributes.find( + (attr) => attr.decl.ref?.name === 'allow' + ); + } + + private generateRequestRuntime(project: Project, context: Context) { + const content = ` + import useSWR, { useSWRConfig } from 'swr'; + import type { ScopedMutator } from 'swr/dist/types'; + + const fetcher = async (url: string, options?: RequestInit) => { + const res = await fetch(url, options); + if (!res.ok) { + const error: Error & { info?: any; status?: number } = new Error( + 'An error occurred while fetching the data.' + ); + error.info = await res.json(); + error.status = res.status; + throw error; + } + return res.json(); + }; + + function makeUrl(url: string, args: unknown) { + return args ? url + \`q=\${encodeURIComponent(JSON.stringify(args))}\` : url; + } + + export function get(url: string, args?: unknown) { + return useSWR(makeUrl(url, args), fetcher); + } + + export async function post( + url: string, + data: Data, + mutate: ScopedMutator + ) { + const r: Result = await fetcher(url, { + method: 'POST', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify(data), + }); + mutate(url); + return r; + } + + export async function put( + url: string, + data: Data, + mutate: ScopedMutator + ) { + const r: Result = await fetcher(url, { + method: 'PUT', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify(data), + }); + mutate(url, r); + return r; + } + + export async function del( + url: string, + args: unknown, + mutate: ScopedMutator + ) { + const reqUrl = makeUrl(url, args); + const r: Result = await fetcher(reqUrl, { + method: 'DELETE', + }); + const path = url.split('/'); + path.pop(); + mutate(path.join('/')); + return r; + } + + export function getMutate() { + const { mutate } = useSWRConfig(); + return mutate; + } + `; + + const sf = project.createSourceFile( + path.join(context.outDir, `hooks/request.ts`), + content, + { overwrite: true } + ); + sf.formatText(); + } + + private generateModelHooks( + project: Project, + context: Context, + model: DataModel + ) { + const fileName = paramCase(model.name); + const sf = project.createSourceFile( + path.join(context.outDir, `hooks/${fileName}.ts`), + undefined, + { overwrite: true } + ); + + sf.addImportDeclaration({ + namedImports: [{ name: 'Prisma', alias: 'P' }, model.name], + isTypeOnly: true, + moduleSpecifier: '../.prisma', + }); + + sf.addStatements([`import * as request from './request';`]); + + sf.addStatements( + `const endpoint = '/api/zen/data/${camelCase(model.name)}';` + ); + + const useFuncBody = sf + .addFunction({ + name: `use${model.name}`, + isExported: true, + }) + .addBody(); + + useFuncBody.addStatements(['const mutate = request.getMutate();']); + + // create + useFuncBody + .addFunction({ + name: 'create', + isAsync: true, + typeParameters: [`T extends P.${model.name}CreateArgs`], + parameters: [ + { name: 'args', type: `P.${model.name}CreateArgs` }, + ], + }) + .addBody() + .addStatements([ + `return request.post>>(endpoint, args, mutate);`, + ]); + + // find + useFuncBody + .addFunction({ + name: 'find', + isAsync: true, + typeParameters: [`T extends P.${model.name}FindManyArgs`], + parameters: [ + { + name: 'args?', + type: `P.SelectSubset`, + }, + ], + }) + .addBody() + .addStatements([ + `return request.get, Array>>>(endpoint, args);`, + ]); + + // get + useFuncBody + .addFunction({ + name: 'get', + isAsync: true, + typeParameters: [ + `T extends P.Subset`, + ], + parameters: [ + { + name: 'id', + type: 'String', + }, + { + name: 'args?', + type: `P.SelectSubset>`, + }, + ], + }) + .addBody() + .addStatements([ + `return request.get>>(\`\${endpoint}/\${id}\`, args);`, + ]); + + // update + useFuncBody + .addFunction({ + name: 'update', + isAsync: true, + typeParameters: [ + `T extends Omit`, + ], + parameters: [ + { name: 'id', type: 'String' }, + { + name: 'args', + type: `Omit`, + }, + ], + }) + .addBody() + .addStatements([ + `return request.put, P.CheckSelect>>(\`\${endpoint}/\${id}\`, args, mutate);`, + ]); + + // del + useFuncBody + .addFunction({ + name: 'del', + isAsync: true, + typeParameters: [ + `T extends Omit`, + ], + parameters: [ + { name: 'id', type: 'String' }, + { + name: 'args', + type: `Omit`, + }, + ], + }) + .addBody() + .addStatements([ + `return request.del>>(\`\${endpoint}/\${id}\`, args, mutate);`, + ]); + + useFuncBody.addStatements([ + 'return { create, find, get, update, del };', + ]); + + sf.formatText(); + } + + private generateIndex( + project: Project, + context: Context, + models: DataModel[] + ) { + const sf = project.createSourceFile( + path.join(context.outDir, 'hooks/index.ts'), + undefined, + { overwrite: true } + ); + + sf.addStatements( + models.map((d) => `export * from './${paramCase(d.name)}';`) + ); + + sf.formatText(); + } +} diff --git a/packages/schema/src/generator/service/index.ts b/packages/schema/src/generator/service/index.ts new file mode 100644 index 000000000..9d7ab4138 --- /dev/null +++ b/packages/schema/src/generator/service/index.ts @@ -0,0 +1,43 @@ +import { Context, Generator } from '../types'; +import { Project, StructureKind } from 'ts-morph'; +import * as path from 'path'; +import colors from 'colors'; + +export default class ServiceGenerator implements Generator { + async generate(context: Context) { + const project = new Project(); + const sf = project.createSourceFile( + path.join(context.outDir, 'service.ts'), + undefined, + { overwrite: true } + ); + + sf.addImportDeclaration({ + namedImports: ['PrismaClient'], + moduleSpecifier: './.prisma', + }); + + const cls = sf.addClass({ + name: 'ZenStackService', + isExported: true, + }); + cls.addMember({ + kind: StructureKind.Property, + name: 'private readonly _prisma', + initializer: 'new PrismaClient()', + }); + + cls.addGetAccessor({ + name: 'prisma', + }) + .addBody() + .setBodyText('return this._prisma;'); + + sf.addStatements(['export default new ZenStackService();']); + + sf.formatText(); + await project.save(); + + console.log(colors.blue(`ZenStack service generated`)); + } +} diff --git a/packages/schema/src/language-server/stdlib.zmodel b/packages/schema/src/language-server/stdlib.zmodel index 465d19dac..fbacd737b 100644 --- a/packages/schema/src/language-server/stdlib.zmodel +++ b/packages/schema/src/language-server/stdlib.zmodel @@ -5,6 +5,8 @@ enum ReferentialIntegrity { function env() String {} function auth() User {} function now() DateTime {} +function uuid() String {} +function cuid() String {} attribute id() attribute index() diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 750c6da5c..2f1d618b4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,30 +3,21 @@ lockfileVersion: 5.4 importers: .: - specifiers: - '@zenstackhq/schema': workspace:* - dependencies: - '@zenstackhq/schema': link:packages/schema + specifiers: {} packages/runtime: specifiers: - '@next-auth/prisma-adapter': ^1.0.4 '@prisma/client': ^4.3.1 - '@types/bcryptjs': ^2.4.2 - bcryptjs: ^2.4.3 - next-auth: ^4.10.3 react: ^17.0.2 || ^18 react-dom: ^17.0.2 || ^18 + swr: ^1.3.0 typescript: ^4.6.2 dependencies: - '@next-auth/prisma-adapter': 1.0.4_bwhncj256yar2zz55r2fl3abo4 '@prisma/client': 4.3.1 - bcryptjs: 2.4.3 - next-auth: 4.10.3_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 + swr: 1.3.0_react@18.2.0 devDependencies: - '@types/bcryptjs': 2.4.2 typescript: 4.8.3 packages/schema: @@ -39,6 +30,7 @@ importers: '@types/vscode': ^1.56.0 '@typescript-eslint/eslint-plugin': ^4.14.1 '@typescript-eslint/parser': ^4.14.1 + change-case: ^4.1.2 chevrotain: ^9.1.0 colors: ^1.4.0 commander: ^8.0.0 @@ -47,21 +39,24 @@ importers: jest: ^29.0.3 langium: ^0.4.0 langium-cli: ^0.4.0 + promisify: ^0.0.3 tmp: ^0.2.1 ts-jest: ^29.0.1 + ts-morph: ^16.0.0 ts-node: ^10.9.1 typescript: ^4.6.2 - uuid: ^9.0.0 vscode-jsonrpc: ^8.0.2 vscode-languageclient: ^7.0.0 vscode-languageserver: ^7.0.0 vscode-uri: ^3.0.2 dependencies: + change-case: 4.1.2 chevrotain: 9.1.0 colors: 1.4.0 commander: 8.3.0 langium: 0.4.0 - uuid: 9.0.0 + promisify: 0.0.3 + ts-morph: 16.0.0 vscode-jsonrpc: 8.0.2 vscode-languageclient: 7.0.0 vscode-languageserver: 7.0.0 @@ -85,6 +80,45 @@ importers: typescript: 4.8.3 samples/todo: + specifiers: + '@types/bcryptjs': ^2.4.2 + '@types/node': ^14.17.3 + '@types/react': 18.0.21 + '@types/react-dom': 18.0.6 + autoprefixer: ^10.4.12 + daisyui: ^2.31.0 + eslint: ^7.19.0 + eslint-config-next: 12.3.1 + next: 12.3.1 + next-auth: ^4.10.3 + postcss: ^8.4.16 + prisma: ^4.4.0 + react: 18.2.0 + react-dom: 18.2.0 + swr: ^1.3.0 + tailwindcss: ^3.1.8 + typescript: ^4.6.2 + dependencies: + daisyui: 2.31.0_jhfe3rbur6kzimvcehnoniy6fy + next: 12.3.1_biqbaboplfbrettd7655fr4n2y + next-auth: 4.10.3_biqbaboplfbrettd7655fr4n2y + prisma: 4.4.0 + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + swr: 1.3.0_react@18.2.0 + devDependencies: + '@types/bcryptjs': 2.4.2 + '@types/node': 14.18.29 + '@types/react': 18.0.21 + '@types/react-dom': 18.0.6 + autoprefixer: 10.4.12_postcss@8.4.16 + eslint: 7.32.0 + eslint-config-next: 12.3.1_dyxdave6dwjbccc5dgiifcmuza + postcss: 8.4.16 + tailwindcss: 3.1.8_postcss@8.4.16 + typescript: 4.8.3 + + samples/todo-target: specifiers: '@prisma/client': ^4.3.1 '@types/bcryptjs': ^2.4.2 @@ -105,7 +139,7 @@ importers: tailwindcss: ^3.1.8 typescript: ^4.6.2 dependencies: - '@prisma/client': 4.3.1_prisma@4.3.1 + '@prisma/client': 4.3.1_prisma@4.4.0 daisyui: 2.31.0_jhfe3rbur6kzimvcehnoniy6fy next: 12.3.1_biqbaboplfbrettd7655fr4n2y next-auth: 4.10.3_biqbaboplfbrettd7655fr4n2y @@ -121,7 +155,7 @@ importers: eslint: 7.32.0 eslint-config-next: 12.3.1_dyxdave6dwjbccc5dgiifcmuza postcss: 8.4.16 - prisma: 4.3.1 + prisma: 4.4.0 tailwindcss: 3.1.8_postcss@8.4.16 typescript: 4.8.3 @@ -891,16 +925,6 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true - /@next-auth/prisma-adapter/1.0.4_bwhncj256yar2zz55r2fl3abo4: - resolution: {integrity: sha512-jIOM6CzCbl2/Mzbx9kb2IjtHoJOeRN9wtQgLk4EUm5bhneSVGv1rtz5TDskvp2UfCa+EK9nDmug+lje41z80Gg==} - peerDependencies: - '@prisma/client': '>=2.26.0 || >=3' - next-auth: ^4 - dependencies: - '@prisma/client': 4.3.1 - next-auth: 4.10.3_biqbaboplfbrettd7655fr4n2y - dev: false - /@next/env/12.3.1: resolution: {integrity: sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==} dev: false @@ -1106,7 +1130,7 @@ packages: '@prisma/engines-version': 4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b dev: false - /@prisma/client/4.3.1_prisma@4.3.1: + /@prisma/client/4.3.1_prisma@4.4.0: resolution: {integrity: sha512-FA0/d1VMJNWqzU7WVWTNWJ+lGOLR9JUBnF73GdIPAEVo/6dWk4gHx0EmgeU+SMv4MZoxgOeTBJF2azhg7x0hMw==} engines: {node: '>=14.17'} requiresBuild: true @@ -1117,7 +1141,7 @@ packages: optional: true dependencies: '@prisma/engines-version': 4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b - prisma: 4.3.1 + prisma: 4.4.0 dev: false /@prisma/debug/4.4.0: @@ -1155,14 +1179,9 @@ packages: resolution: {integrity: sha512-8yWpXkQRmiSfsi2Wb/ZS5D3RFbeu/btL9Pm/gdF4phB0Lo5KGsDFMxFMgaD64mwED2nHc8ZaEJg/+4Jymb9Znw==} dev: false - /@prisma/engines/4.3.1: - resolution: {integrity: sha512-4JF/uMaEDAPdcdZNOrnzE3BvrbGpjgV0FcPT3EVoi6I86fWkloqqxBt+KcK/+fIRR0Pxj66uGR9wVH8U1Y13JA==} - requiresBuild: true - /@prisma/engines/4.4.0: resolution: {integrity: sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==} requiresBuild: true - dev: true /@prisma/fetch-engine/4.4.0: resolution: {integrity: sha512-3a+f/HPvJl9XYj8IuX57/rHM8cYZuqS+R+jXx/ZPRwvELVlvVeE81GTTSMvtXguyfHXgKW7wKjiJqZm7tGw/WA==} @@ -1295,6 +1314,15 @@ packages: engines: {node: '>= 10'} dev: true + /@ts-morph/common/0.17.0: + resolution: {integrity: sha512-RMSSvSfs9kb0VzkvQ2NWobwnj7TxCA9vI/IjR9bDHqgAyVbu2T0DN4wiKVqomyDWqO7dPr/tErSfq7urQ1Q37g==} + dependencies: + fast-glob: 3.2.12 + minimatch: 5.1.0 + mkdirp: 1.0.4 + path-browserify: 1.0.1 + dev: false + /@tsconfig/node10/1.0.9: resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==} dev: true @@ -1953,10 +1981,6 @@ packages: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} dev: true - /bcryptjs/2.4.3: - resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} - dev: false - /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} @@ -1979,7 +2003,6 @@ packages: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - dev: true /braces/3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} @@ -2037,6 +2060,13 @@ packages: engines: {node: '>=6'} dev: true + /camel-case/4.1.2: + resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} + dependencies: + pascal-case: 3.1.2 + tslib: 2.4.0 + dev: false + /camelcase-css/2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} @@ -2054,6 +2084,14 @@ packages: /caniuse-lite/1.0.30001409: resolution: {integrity: sha512-V0mnJ5dwarmhYv8/MzhJ//aW68UpvnQBXv8lJ2QUsvn2pHcmAuNtu8hQEDz37XnA1iE+lRR9CIfGWWpgJ5QedQ==} + /capital-case/1.0.4: + resolution: {integrity: sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==} + dependencies: + no-case: 3.0.4 + tslib: 2.4.0 + upper-case-first: 2.0.2 + dev: false + /chalk/2.4.2: resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} engines: {node: '>=4'} @@ -2071,6 +2109,23 @@ packages: supports-color: 7.2.0 dev: true + /change-case/4.1.2: + resolution: {integrity: sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==} + dependencies: + camel-case: 4.1.2 + capital-case: 1.0.4 + constant-case: 3.0.4 + dot-case: 3.0.4 + header-case: 2.0.4 + no-case: 3.0.4 + param-case: 3.0.4 + pascal-case: 3.1.2 + path-case: 3.0.4 + sentence-case: 3.0.4 + snake-case: 3.0.4 + tslib: 2.4.0 + dev: false + /char-regex/1.0.2: resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} engines: {node: '>=10'} @@ -2166,6 +2221,10 @@ packages: engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} dev: true + /code-block-writer/11.0.3: + resolution: {integrity: sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==} + dev: false + /collect-v8-coverage/1.0.1: resolution: {integrity: sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==} dev: true @@ -2251,6 +2310,14 @@ packages: yargs: 17.5.1 dev: true + /constant-case/3.0.4: + resolution: {integrity: sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==} + dependencies: + no-case: 3.0.4 + tslib: 2.4.0 + upper-case: 2.0.2 + dev: false + /convert-source-map/1.8.0: resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} dependencies: @@ -2363,7 +2430,7 @@ packages: supports-color: optional: true dependencies: - ms: 2.1.2 + ms: 2.1.3 dev: true /debug/4.3.4: @@ -2473,6 +2540,13 @@ packages: esutils: 2.0.3 dev: true + /dot-case/3.0.4: + resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dependencies: + no-case: 3.0.4 + tslib: 2.4.0 + dev: false + /dotenv/16.0.2: resolution: {integrity: sha512-JvpYKUmzQhYoIFgK2MOnF3bciIZoItIIoryihy0rIA+H4Jy0FmgyKYAHCTN98P5ybGSJcIFbh6QKeJdtZd1qhA==} engines: {node: '>=12'} @@ -3225,6 +3299,13 @@ packages: type-fest: 0.8.1 dev: true + /header-case/2.0.4: + resolution: {integrity: sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==} + dependencies: + capital-case: 1.0.4 + tslib: 2.4.0 + dev: false + /hosted-git-info/2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: true @@ -4184,6 +4265,12 @@ packages: dependencies: js-tokens: 4.0.0 + /lower-case/2.0.2: + resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + dependencies: + tslib: 2.4.0 + dev: false + /lru-cache/6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -4242,11 +4329,16 @@ packages: engines: {node: '>=10'} dependencies: brace-expansion: 2.0.1 - dev: true /minimist/1.2.6: resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} + /mkdirp/1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + dev: false + /ms/2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} dev: true @@ -4342,6 +4434,13 @@ packages: - babel-plugin-macros dev: false + /no-case/3.0.4: + resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + dependencies: + lower-case: 2.0.2 + tslib: 2.4.0 + dev: false + /node-fetch/2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} engines: {node: 4.x || >=6.0.0} @@ -4579,6 +4678,13 @@ packages: engines: {node: '>=6'} dev: true + /param-case/3.0.4: + resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} + dependencies: + dot-case: 3.0.4 + tslib: 2.4.0 + dev: false + /parent-module/1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -4596,6 +4702,24 @@ packages: lines-and-columns: 1.2.4 dev: true + /pascal-case/3.1.2: + resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + dependencies: + no-case: 3.0.4 + tslib: 2.4.0 + dev: false + + /path-browserify/1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: false + + /path-case/3.0.4: + resolution: {integrity: sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==} + dependencies: + dot-case: 3.0.4 + tslib: 2.4.0 + dev: false + /path-exists/4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -4745,13 +4869,13 @@ packages: resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} dev: false - /prisma/4.3.1: - resolution: {integrity: sha512-90xo06wtqil76Xsi3mNpc4Js3SdDRR5g4qb9h+4VWY4Y8iImJY6xc3PX+C9xxTSt1lr0Q89A0MLkJjd8ax6KiQ==} + /prisma/4.4.0: + resolution: {integrity: sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==} engines: {node: '>=14.17'} hasBin: true requiresBuild: true dependencies: - '@prisma/engines': 4.3.1 + '@prisma/engines': 4.4.0 /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -4762,6 +4886,12 @@ packages: engines: {node: '>=0.4.0'} dev: true + /promisify/0.0.3: + resolution: {integrity: sha512-CcBGsRhhq466fsZVyHfptuKqon6eih0CqMsJE0kWIIjbpVNEyDoaKLELm2WVs//W/WXRBHip+6xhTExTkHUwtA==} + dependencies: + when: 3.7.8 + dev: false + /prompts/2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -5020,6 +5150,14 @@ packages: dependencies: lru-cache: 6.0.0 + /sentence-case/3.0.4: + resolution: {integrity: sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==} + dependencies: + no-case: 3.0.4 + tslib: 2.4.0 + upper-case-first: 2.0.2 + dev: false + /shebang-command/2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -5081,6 +5219,13 @@ packages: is-fullwidth-code-point: 3.0.0 dev: true + /snake-case/3.0.4: + resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + dependencies: + dot-case: 3.0.4 + tslib: 2.4.0 + dev: false + /source-map-js/1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} @@ -5455,6 +5600,13 @@ packages: yargs-parser: 21.1.1 dev: true + /ts-morph/16.0.0: + resolution: {integrity: sha512-jGNF0GVpFj0orFw55LTsQxVYEUOCWBAbR5Ls7fTYE5pQsbW18ssTb/6UXx/GYAEjS+DQTp8VoTw0vqYMiaaQuw==} + dependencies: + '@ts-morph/common': 0.17.0 + code-block-writer: 11.0.3 + dev: false + /ts-node/10.9.1_ck2axrxkiif44rdbzjywaqjysa: resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true @@ -5595,6 +5747,18 @@ packages: escalade: 3.1.1 picocolors: 1.0.0 + /upper-case-first/2.0.2: + resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} + dependencies: + tslib: 2.4.0 + dev: false + + /upper-case/2.0.2: + resolution: {integrity: sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==} + dependencies: + tslib: 2.4.0 + dev: false + /uri-js/4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} dependencies: @@ -5622,11 +5786,6 @@ packages: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true - /uuid/9.0.0: - resolution: {integrity: sha512-MXcSTerfPa4uqyzStbRoTgt5XIe3x5+42+q1sDuy3R5MDk66URdLMOZe5aPX/SQd+kuYAh0FdP/pO28IkQyTeg==} - hasBin: true - dev: false - /v8-compile-cache-lib/3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} dev: true @@ -5713,6 +5872,10 @@ packages: webidl-conversions: 3.0.1 dev: true + /when/3.7.8: + resolution: {integrity: sha512-5cZ7mecD3eYcMiCH4wtRPA5iFJZ50BJYDfckI5RRpQiktMiYTcn0ccLTZOvcbBume+1304fQztxeNzNS9Gvrnw==} + dev: false + /which-boxed-primitive/1.0.2: resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} dependencies: diff --git a/samples/todo-target/.zenstack/client.ts b/samples/todo-target/.zenstack/client.ts index 7b4f36ea7..e316e677d 100644 --- a/samples/todo-target/.zenstack/client.ts +++ b/samples/todo-target/.zenstack/client.ts @@ -1,22 +1,9 @@ import { PrismaClient } from './.prisma'; export class ZenStackClient { - readonly prisma: PrismaClient; + readonly prisma = new PrismaClient(); - constructor() { - this.prisma = new PrismaClient(); - this.prisma.todoList.findMany({ - select: { - title: true, - }, - where: { - title: { - contains: 'hello', - }, - }, - }); - } + constructor() {} } -const client = new ZenStackClient(); -export default client; +export default new ZenStackClient(); diff --git a/samples/todo-target/.zenstack/hooks/todo-list.ts b/samples/todo-target/.zenstack/hooks/todo-list.ts index 3091d22a5..186797f78 100644 --- a/samples/todo-target/.zenstack/hooks/todo-list.ts +++ b/samples/todo-target/.zenstack/hooks/todo-list.ts @@ -1,16 +1,5 @@ import { useSWRConfig } from 'swr'; -import { - TodoListCreateArgs, - TodoListCreateResult, - TodoListDeleteArgs, - TodoListFindArgs, - TodoListFindArgsInput, - TodoListFindResult, - TodoListGetArgs, - TodoListGetArgsInput, - TodoListUpdateArgs, - TodoListUpdateResult, -} from '../types'; +import type { Prisma, TodoList } from '../.prisma'; import { put, del as _del, post, swr } from './request'; const base = '/api/zen/data/todoList'; @@ -18,52 +7,75 @@ const base = '/api/zen/data/todoList'; export function useTodoList() { const { mutate } = useSWRConfig(); - async function create( - data: TodoListCreateArgs + async function create( + data: Prisma.TodoListCreateArgs ) { - return post>( - base, - data, - mutate - ); + return post< + Prisma.TodoListCreateArgs, + Prisma.CheckSelect> + >(base, data, mutate); } - function find(args?: TodoListFindArgs) { + function find( + args?: Prisma.SelectSubset + ) { let endpoint = base; if (args) { endpoint += `?q=${encodeURIComponent(JSON.stringify(args))}`; } - return swr>(endpoint); + return swr< + Prisma.CheckSelect< + T, + Array, + Array> + > + >(endpoint); } - function get( + function get< + T extends Pick + >( id: string, - args?: TodoListGetArgs + args?: Prisma.SelectSubset< + T, + Pick + > ) { let endpoint = `${base}/${id}`; if (args) { endpoint += `?q=${encodeURIComponent(JSON.stringify(args))}`; } - return swr>(endpoint); + return swr< + Prisma.CheckSelect> + >(endpoint); } - async function update( + async function update>( id: string, - data: TodoListUpdateArgs + data: Omit ) { - return put>( - `${base}/batch`, - data, - mutate - ); + const payload = { + ...data, + where: { id }, + }; + return put< + Prisma.TodoListUpdateArgs, + Prisma.CheckSelect> + >(`${base}/batch`, payload, mutate); } - async function del(id: string, args?: TodoListDeleteArgs) { + async function del>( + id: string, + args?: Omit + ) { let url = `${base}/${id}`; if (args) { url += `?q=${encodeURIComponent(JSON.stringify(args))}`; } - return _del(url, mutate); + + return _del< + Prisma.CheckSelect> + >(url, mutate); } return { create, find, get, update, del }; diff --git a/samples/todo/functions/invite-user.ts b/samples/todo/functions/invite-user.ts deleted file mode 100644 index 7f4e79f14..000000000 --- a/samples/todo/functions/invite-user.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { SpaceUserRole } from '@zenstack/.prisma'; -import { FunctionContext } from '@zenstack/types'; - -async function func( - context: FunctionContext, - spaceId: string, - userId: string, - role: SpaceUserRole -) { - const r = await context.db.spaceUser.create({ - data: { - userId, - spaceId, - role, - }, - }); - // send email - return r; -} - -export default func; diff --git a/samples/todo/package-lock.json b/samples/todo/package-lock.json new file mode 100644 index 000000000..d994ee76f --- /dev/null +++ b/samples/todo/package-lock.json @@ -0,0 +1,6804 @@ +{ + "name": "todo", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "todo", + "version": "0.1.0", + "dependencies": { + "@prisma/client": "^4.4.0", + "@zenstackhq/runtime": "^0.1.1", + "daisyui": "^2.31.0", + "next": "12.3.1", + "next-auth": "^4.10.3", + "prisma": "^4.4.0", + "react": "18.2.0", + "react-dom": "18.2.0", + "swr": "^1.3.0" + }, + "devDependencies": { + "@types/bcryptjs": "^2.4.2", + "@types/node": "^14.17.3", + "@types/react": "18.0.21", + "@types/react-dom": "18.0.6", + "autoprefixer": "^10.4.12", + "eslint": "^7.19.0", + "eslint-config-next": "12.3.1", + "postcss": "^8.4.16", + "tailwindcss": "^3.1.8", + "typescript": "^4.6.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/runtime": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", + "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs3": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz", + "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==", + "dev": true, + "dependencies": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@next/env": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.1.tgz", + "integrity": "sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-12.3.1.tgz", + "integrity": "sha512-sw+lTf6r6P0j+g/n9y4qdWWI2syPqZx+uc0+B/fRENqfR3KpSid6MIKqc9gNwGhJASazEQ5b3w8h4cAET213jw==", + "dev": true, + "dependencies": { + "glob": "7.1.7" + } + }, + "node_modules/@next/swc-android-arm-eabi": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.1.tgz", + "integrity": "sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-android-arm64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.1.tgz", + "integrity": "sha512-CmgU2ZNyBP0rkugOOqLnjl3+eRpXBzB/I2sjwcGZ7/Z6RcUJXK5Evz+N0ucOxqE4cZ3gkTeXtSzRrMK2mGYV8Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.1.tgz", + "integrity": "sha512-hT/EBGNcu0ITiuWDYU9ur57Oa4LybD5DOQp4f22T6zLfpoBMfBibPtR8XktXmOyFHrL/6FC2p9ojdLZhWhvBHg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.1.tgz", + "integrity": "sha512-9S6EVueCVCyGf2vuiLiGEHZCJcPAxglyckTZcEwLdJwozLqN0gtS0Eq0bQlGS3dH49Py/rQYpZ3KVWZ9BUf/WA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-freebsd-x64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.1.tgz", + "integrity": "sha512-qcuUQkaBZWqzM0F1N4AkAh88lLzzpfE6ImOcI1P6YeyJSsBmpBIV8o70zV+Wxpc26yV9vpzb+e5gCyxNjKJg5Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm-gnueabihf": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.1.tgz", + "integrity": "sha512-diL9MSYrEI5nY2wc/h/DBewEDUzr/DqBjIgHJ3RUNtETAOB3spMNHvJk2XKUDjnQuluLmFMloet9tpEqU2TT9w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.1.tgz", + "integrity": "sha512-o/xB2nztoaC7jnXU3Q36vGgOolJpsGG8ETNjxM1VAPxRwM7FyGCPHOMk1XavG88QZSQf+1r+POBW0tLxQOJ9DQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.1.tgz", + "integrity": "sha512-2WEasRxJzgAmP43glFNhADpe8zB7kJofhEAVNbDJZANp+H4+wq+/cW1CdDi8DqjkShPEA6/ejJw+xnEyDID2jg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.1.tgz", + "integrity": "sha512-JWEaMyvNrXuM3dyy9Pp5cFPuSSvG82+yABqsWugjWlvfmnlnx9HOQZY23bFq3cNghy5V/t0iPb6cffzRWylgsA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.1.tgz", + "integrity": "sha512-xoEWQQ71waWc4BZcOjmatuvPUXKTv6MbIFzpm4LFeCHsg2iwai0ILmNXf81rJR+L1Wb9ifEke2sQpZSPNz1Iyg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.1.tgz", + "integrity": "sha512-hswVFYQYIeGHE2JYaBVtvqmBQ1CppplQbZJS/JgrVI3x2CurNhEkmds/yqvDONfwfbttTtH4+q9Dzf/WVl3Opw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.1.tgz", + "integrity": "sha512-Kny5JBehkTbKPmqulr5i+iKntO5YMP+bVM8Hf8UAmjSMVo3wehyLVc9IZkNmcbxi+vwETnQvJaT5ynYBkJ9dWA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.1.tgz", + "integrity": "sha512-W1ijvzzg+kPEX6LAc+50EYYSEo0FVu7dmTE+t+DM4iOLqgGHoW9uYSz9wCVdkXOEEMP9xhXfGpcSxsfDucyPkA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@panva/hkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.0.2.tgz", + "integrity": "sha512-MSAs9t3Go7GUkMhpKC44T58DJ5KGk2vBo+h1cqQeqlMfdGkxaVB78ZWpv9gYi/g2fa4sopag9gJsNvS8XGgWJA==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/@prisma/client": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.4.0.tgz", + "integrity": "sha512-ciKOP246x1xwr04G9ajHlJ4pkmtu9Q6esVyqVBO0QJihaKQIUvbPjClp17IsRJyxqNpFm4ScbOc/s9DUzKHINQ==", + "hasInstallScript": true, + "dependencies": { + "@prisma/engines-version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6" + }, + "engines": { + "node": ">=14.17" + }, + "peerDependencies": { + "prisma": "*" + }, + "peerDependenciesMeta": { + "prisma": { + "optional": true + } + } + }, + "node_modules/@prisma/engines": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.4.0.tgz", + "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==", + "hasInstallScript": true + }, + "node_modules/@prisma/engines-version": { + "version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6.tgz", + "integrity": "sha512-P5v/PuEIJLYXZUZBvOLPqoyCW+m6StNqHdiR6te++gYVODpPdLakks5HVx3JaZIY+LwR02juJWFlwpc9Eog/ug==" + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", + "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", + "dev": true + }, + "node_modules/@swc/helpers": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz", + "integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/bcryptjs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", + "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "14.18.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.31.tgz", + "integrity": "sha512-vQAnaReSQkEDa8uwAyQby8bYGKu84R/deEc6mg5T8fX6gzCn8QW6rziSgsti1fNvsrswKUKPnVTi7uoB+u62Mw==", + "dev": true + }, + "node_modules/@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "dev": true + }, + "node_modules/@types/react": { + "version": "18.0.21", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz", + "integrity": "sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==", + "dev": true, + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", + "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.39.0.tgz", + "integrity": "sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.39.0", + "@typescript-eslint/types": "5.39.0", + "@typescript-eslint/typescript-estree": "5.39.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.39.0.tgz", + "integrity": "sha512-/I13vAqmG3dyqMVSZPjsbuNQlYS082Y7OMkwhCfLXYsmlI0ca4nkL7wJ/4gjX70LD4P8Hnw1JywUVVAwepURBw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.39.0", + "@typescript-eslint/visitor-keys": "5.39.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.39.0.tgz", + "integrity": "sha512-gQMZrnfEBFXK38hYqt8Lkwt8f4U6yq+2H5VDSgP/qiTzC8Nw8JO3OuSUOQ2qW37S/dlwdkHDntkZM6SQhKyPhw==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.39.0.tgz", + "integrity": "sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.39.0", + "@typescript-eslint/visitor-keys": "5.39.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.39.0.tgz", + "integrity": "sha512-yyE3RPwOG+XJBLrhvsxAidUgybJVQ/hG8BhiJo0k8JSAYfk/CshVcxf0HwP4Jt7WZZ6vLmxdo1p6EyN3tzFTkg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.39.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@zenstackhq/runtime": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@zenstackhq/runtime/-/runtime-0.1.1.tgz", + "integrity": "sha512-QsgMjOu5BZKcCPOSZVP32bqHjL1YeUNlarzygqZkMpKK89yZTpqYvrG2VGIUOLj3ESvkn0Cr+D7OlzsE8ZayOA==", + "dependencies": { + "swr": "^1.3.0" + }, + "peerDependencies": { + "react": "^17.0.2 || ^18", + "react-dom": "^17.0.2 || ^18" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/array-includes": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.12", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.12.tgz", + "integrity": "sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + } + ], + "dependencies": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001407", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axe-core": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz", + "integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001415", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001415.tgz", + "integrity": "sha512-ER+PfgCJUe8BqunLGWd/1EY4g8AzQcsDAVzdtMGKVtQEmKAwaFfU6vb7EAVIqTMYsqxBorYZi2+22Iouj/y7GQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "dependencies": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + }, + "engines": { + "node": ">=12.5.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-js-pure": { + "version": "3.25.5", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.5.tgz", + "integrity": "sha512-oml3M22pHM+igfWHDfdLVq2ShWmjM2V4L+dQEBs0DWVIqEm9WHCwGAlZ6BmyBQGy5sFrJmcx+856D9lVKyGWYg==", + "dev": true, + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css-selector-tokenizer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz", + "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==", + "dependencies": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "dev": true + }, + "node_modules/daisyui": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.31.0.tgz", + "integrity": "sha512-qepRXgQPLNcJ8ZPZy+dUvsC7mRWvMLRcVMe85/wZA60Tnhm/bkidhOzdllL8aAk2JX+W/xlIsTJ8NZFpPm+eyw==", + "dependencies": { + "color": "^4.2", + "css-selector-tokenizer": "^0.8.0", + "postcss-js": "^4.0.0", + "tailwindcss": "^3" + }, + "peerDependencies": { + "autoprefixer": "^10.0.2", + "postcss": "^8.1.6" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "dependencies": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==" + }, + "node_modules/detective": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", + "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", + "dependencies": { + "acorn-node": "^1.8.2", + "defined": "^1.0.0", + "minimist": "^1.2.6" + }, + "bin": { + "detective": "bin/detective.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.271", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.271.tgz", + "integrity": "sha512-BCPBtK07xR1/uY2HFDtl3wK2De66AW4MSiPlLrnPNxKC/Qhccxd59W73654S3y6Rb/k3hmuGJOBnhjfoutetXA==" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/es-abstract": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.3.tgz", + "integrity": "sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.6", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-next": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-12.3.1.tgz", + "integrity": "sha512-EN/xwKPU6jz1G0Qi6Bd/BqMnHLyRAL0VsaQaWA7F3KkjAgZHi4f1uL1JKGWNxdQpHTW/sdGONBd0bzxUka/DJg==", + "dev": true, + "dependencies": { + "@next/eslint-plugin-next": "12.3.1", + "@rushstack/eslint-patch": "^1.1.3", + "@typescript-eslint/parser": "^5.21.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^2.7.1", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.31.7", + "eslint-plugin-react-hooks": "^4.5.0" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz", + "integrity": "sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "glob": "^7.2.0", + "is-glob": "^4.0.3", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-import-resolver-typescript/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz", + "integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.18.9", + "aria-query": "^4.2.2", + "array-includes": "^3.1.5", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.4.3", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.2", + "language-tags": "^1.0.5", + "minimatch": "^3.1.2", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.31.8", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", + "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.5", + "array.prototype.flatmap": "^1.3.0", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.1", + "object.values": "^1.1.5", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-scope/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^1.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "dependencies": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/espree/node_modules/eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://www.patreon.com/infusion" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "node_modules/function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jose": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.10.0.tgz", + "integrity": "sha512-KEhB/eLGLomWGPTb+/RNbYsTjIyx03JmbqAyIyiXBuNSa7CmNrJd5ysFhblayzs/e/vbOPMUaLnjHUMhGp4yLw==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "dev": true, + "dependencies": { + "language-subtag-registry": "~0.3.2" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lilconfig": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", + "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/next": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/next/-/next-12.3.1.tgz", + "integrity": "sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==", + "dependencies": { + "@next/env": "12.3.1", + "@swc/helpers": "0.4.11", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.0.7", + "use-sync-external-store": "1.2.0" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=12.22.0" + }, + "optionalDependencies": { + "@next/swc-android-arm-eabi": "12.3.1", + "@next/swc-android-arm64": "12.3.1", + "@next/swc-darwin-arm64": "12.3.1", + "@next/swc-darwin-x64": "12.3.1", + "@next/swc-freebsd-x64": "12.3.1", + "@next/swc-linux-arm-gnueabihf": "12.3.1", + "@next/swc-linux-arm64-gnu": "12.3.1", + "@next/swc-linux-arm64-musl": "12.3.1", + "@next/swc-linux-x64-gnu": "12.3.1", + "@next/swc-linux-x64-musl": "12.3.1", + "@next/swc-win32-arm64-msvc": "12.3.1", + "@next/swc-win32-ia32-msvc": "12.3.1", + "@next/swc-win32-x64-msvc": "12.3.1" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^6.0.0 || ^7.0.0", + "react": "^17.0.2 || ^18.0.0-0", + "react-dom": "^17.0.2 || ^18.0.0-0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next-auth": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.12.2.tgz", + "integrity": "sha512-B25iFUIKYa2pRMWRFPIQWv84WJydqIsv6EbriNuzqNSZnxnlmpsrmJrTeMMLf+9a3qf9FG8enxDmDntmwnBkDQ==", + "dependencies": { + "@babel/runtime": "^7.16.3", + "@panva/hkdf": "^1.0.1", + "cookie": "^0.5.0", + "jose": "^4.9.3", + "oauth": "^0.9.15", + "openid-client": "^5.1.0", + "preact": "^10.6.3", + "preact-render-to-string": "^5.1.19", + "uuid": "^8.3.2" + }, + "engines": { + "node": "^12.19.0 || ^14.15.0 || ^16.13.0" + }, + "peerDependencies": { + "next": "^12.2.5", + "nodemailer": "^6.6.5", + "react": "^17.0.2 || ^18", + "react-dom": "^17.0.2 || ^18" + }, + "peerDependenciesMeta": { + "nodemailer": { + "optional": true + } + } + }, + "node_modules/next/node_modules/postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==" + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.hasown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz", + "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/oidc-token-hash": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz", + "integrity": "sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==", + "engines": { + "node": "^10.13.0 || >=12.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/openid-client": { + "version": "5.1.10", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.1.10.tgz", + "integrity": "sha512-KYAtkxTuUwTvjAmH0QMFFP3i9l0+XhP2/blct6Q9kn+DUJ/lu8/g/bI8ghSgxz9dJLm/9cpB/1uLVGTcGGY0hw==", + "dependencies": { + "jose": "^4.1.4", + "lru-cache": "^6.0.0", + "object-hash": "^2.0.1", + "oidc-token-hash": "^5.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "8.4.17", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz", + "integrity": "sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", + "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", + "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.3.3" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", + "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", + "dependencies": { + "postcss-selector-parser": "^6.0.6" + }, + "engines": { + "node": ">=12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/preact": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.0.tgz", + "integrity": "sha512-Fk6+vB2kb6mSJfDgODq0YDhMfl0HNtK5+Uc9QqECO4nlyPAQwCI+BKyWO//idA7ikV7o+0Fm6LQmNuQi1wXI1w==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/preact" + } + }, + "node_modules/preact-render-to-string": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.4.tgz", + "integrity": "sha512-iIPHb3BXUQ3Za6KNhkjN/waq11Oh+QWWtAgN3id3LrL+cszH3DYh8TxJPNQ6Aogsbu4JsqdJLBZltwPFpG6N6w==", + "dependencies": { + "pretty-format": "^3.8.0" + }, + "peerDependencies": { + "preact": ">=10" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/pretty-format": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", + "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" + }, + "node_modules/prisma": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.4.0.tgz", + "integrity": "sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==", + "hasInstallScript": true, + "dependencies": { + "@prisma/engines": "4.4.0" + }, + "bin": { + "prisma": "build/index.js", + "prisma2": "build/index.js" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.1", + "side-channel": "^1.0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-jsx": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz", + "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==", + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/swr": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/swr/-/swr-1.3.0.tgz", + "integrity": "sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==", + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/table": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", + "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "dev": true, + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/table/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, + "node_modules/tailwindcss": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.8.tgz", + "integrity": "sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==", + "dependencies": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "detective": "^5.2.1", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "lilconfig": "^2.0.6", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.14", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "5.0.6", + "postcss-selector-parser": "^6.0.10", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=12.13.0" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, + "node_modules/tailwindcss/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tailwindcss/node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", + "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist-lint": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "engines": { + "node": ">= 6" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", + "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/runtime": { + "version": "7.19.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", + "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs3": { + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz", + "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==", + "dev": true, + "requires": { + "core-js-pure": "^3.25.1", + "regenerator-runtime": "^0.13.4" + } + }, + "@eslint/eslintrc": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", + "integrity": "sha512-J6KFFz5QCYUJq3pf0mjEcCJVERbzv71PUIDczuh9JkwGEzced6CO5ADLHB1rbf/+oPBtoPfMYNOpGDzCANlbXw==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@next/env": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.1.tgz", + "integrity": "sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==" + }, + "@next/eslint-plugin-next": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-12.3.1.tgz", + "integrity": "sha512-sw+lTf6r6P0j+g/n9y4qdWWI2syPqZx+uc0+B/fRENqfR3KpSid6MIKqc9gNwGhJASazEQ5b3w8h4cAET213jw==", + "dev": true, + "requires": { + "glob": "7.1.7" + } + }, + "@next/swc-android-arm-eabi": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.1.tgz", + "integrity": "sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ==", + "optional": true + }, + "@next/swc-android-arm64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.1.tgz", + "integrity": "sha512-CmgU2ZNyBP0rkugOOqLnjl3+eRpXBzB/I2sjwcGZ7/Z6RcUJXK5Evz+N0ucOxqE4cZ3gkTeXtSzRrMK2mGYV8Q==", + "optional": true + }, + "@next/swc-darwin-arm64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.1.tgz", + "integrity": "sha512-hT/EBGNcu0ITiuWDYU9ur57Oa4LybD5DOQp4f22T6zLfpoBMfBibPtR8XktXmOyFHrL/6FC2p9ojdLZhWhvBHg==", + "optional": true + }, + "@next/swc-darwin-x64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.1.tgz", + "integrity": "sha512-9S6EVueCVCyGf2vuiLiGEHZCJcPAxglyckTZcEwLdJwozLqN0gtS0Eq0bQlGS3dH49Py/rQYpZ3KVWZ9BUf/WA==", + "optional": true + }, + "@next/swc-freebsd-x64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.1.tgz", + "integrity": "sha512-qcuUQkaBZWqzM0F1N4AkAh88lLzzpfE6ImOcI1P6YeyJSsBmpBIV8o70zV+Wxpc26yV9vpzb+e5gCyxNjKJg5Q==", + "optional": true + }, + "@next/swc-linux-arm-gnueabihf": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.1.tgz", + "integrity": "sha512-diL9MSYrEI5nY2wc/h/DBewEDUzr/DqBjIgHJ3RUNtETAOB3spMNHvJk2XKUDjnQuluLmFMloet9tpEqU2TT9w==", + "optional": true + }, + "@next/swc-linux-arm64-gnu": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.1.tgz", + "integrity": "sha512-o/xB2nztoaC7jnXU3Q36vGgOolJpsGG8ETNjxM1VAPxRwM7FyGCPHOMk1XavG88QZSQf+1r+POBW0tLxQOJ9DQ==", + "optional": true + }, + "@next/swc-linux-arm64-musl": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.1.tgz", + "integrity": "sha512-2WEasRxJzgAmP43glFNhADpe8zB7kJofhEAVNbDJZANp+H4+wq+/cW1CdDi8DqjkShPEA6/ejJw+xnEyDID2jg==", + "optional": true + }, + "@next/swc-linux-x64-gnu": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.1.tgz", + "integrity": "sha512-JWEaMyvNrXuM3dyy9Pp5cFPuSSvG82+yABqsWugjWlvfmnlnx9HOQZY23bFq3cNghy5V/t0iPb6cffzRWylgsA==", + "optional": true + }, + "@next/swc-linux-x64-musl": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.1.tgz", + "integrity": "sha512-xoEWQQ71waWc4BZcOjmatuvPUXKTv6MbIFzpm4LFeCHsg2iwai0ILmNXf81rJR+L1Wb9ifEke2sQpZSPNz1Iyg==", + "optional": true + }, + "@next/swc-win32-arm64-msvc": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.1.tgz", + "integrity": "sha512-hswVFYQYIeGHE2JYaBVtvqmBQ1CppplQbZJS/JgrVI3x2CurNhEkmds/yqvDONfwfbttTtH4+q9Dzf/WVl3Opw==", + "optional": true + }, + "@next/swc-win32-ia32-msvc": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.1.tgz", + "integrity": "sha512-Kny5JBehkTbKPmqulr5i+iKntO5YMP+bVM8Hf8UAmjSMVo3wehyLVc9IZkNmcbxi+vwETnQvJaT5ynYBkJ9dWA==", + "optional": true + }, + "@next/swc-win32-x64-msvc": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.1.tgz", + "integrity": "sha512-W1ijvzzg+kPEX6LAc+50EYYSEo0FVu7dmTE+t+DM4iOLqgGHoW9uYSz9wCVdkXOEEMP9xhXfGpcSxsfDucyPkA==", + "optional": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@panva/hkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.0.2.tgz", + "integrity": "sha512-MSAs9t3Go7GUkMhpKC44T58DJ5KGk2vBo+h1cqQeqlMfdGkxaVB78ZWpv9gYi/g2fa4sopag9gJsNvS8XGgWJA==" + }, + "@prisma/client": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-4.4.0.tgz", + "integrity": "sha512-ciKOP246x1xwr04G9ajHlJ4pkmtu9Q6esVyqVBO0QJihaKQIUvbPjClp17IsRJyxqNpFm4ScbOc/s9DUzKHINQ==", + "requires": { + "@prisma/engines-version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6" + } + }, + "@prisma/engines": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.4.0.tgz", + "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==" + }, + "@prisma/engines-version": { + "version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6.tgz", + "integrity": "sha512-P5v/PuEIJLYXZUZBvOLPqoyCW+m6StNqHdiR6te++gYVODpPdLakks5HVx3JaZIY+LwR02juJWFlwpc9Eog/ug==" + }, + "@rushstack/eslint-patch": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.2.0.tgz", + "integrity": "sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==", + "dev": true + }, + "@swc/helpers": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz", + "integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==", + "requires": { + "tslib": "^2.4.0" + } + }, + "@types/bcryptjs": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", + "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", + "dev": true + }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "@types/node": { + "version": "14.18.31", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.31.tgz", + "integrity": "sha512-vQAnaReSQkEDa8uwAyQby8bYGKu84R/deEc6mg5T8fX6gzCn8QW6rziSgsti1fNvsrswKUKPnVTi7uoB+u62Mw==", + "dev": true + }, + "@types/prop-types": { + "version": "15.7.5", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", + "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", + "dev": true + }, + "@types/react": { + "version": "18.0.21", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.0.21.tgz", + "integrity": "sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==", + "dev": true, + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-dom": { + "version": "18.0.6", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.6.tgz", + "integrity": "sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", + "dev": true + }, + "@typescript-eslint/parser": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.39.0.tgz", + "integrity": "sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.39.0", + "@typescript-eslint/types": "5.39.0", + "@typescript-eslint/typescript-estree": "5.39.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.39.0.tgz", + "integrity": "sha512-/I13vAqmG3dyqMVSZPjsbuNQlYS082Y7OMkwhCfLXYsmlI0ca4nkL7wJ/4gjX70LD4P8Hnw1JywUVVAwepURBw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.39.0", + "@typescript-eslint/visitor-keys": "5.39.0" + } + }, + "@typescript-eslint/types": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.39.0.tgz", + "integrity": "sha512-gQMZrnfEBFXK38hYqt8Lkwt8f4U6yq+2H5VDSgP/qiTzC8Nw8JO3OuSUOQ2qW37S/dlwdkHDntkZM6SQhKyPhw==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.39.0.tgz", + "integrity": "sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.39.0", + "@typescript-eslint/visitor-keys": "5.39.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.39.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.39.0.tgz", + "integrity": "sha512-yyE3RPwOG+XJBLrhvsxAidUgybJVQ/hG8BhiJo0k8JSAYfk/CshVcxf0HwP4Jt7WZZ6vLmxdo1p6EyN3tzFTkg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.39.0", + "eslint-visitor-keys": "^3.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", + "dev": true + } + } + }, + "@zenstackhq/runtime": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@zenstackhq/runtime/-/runtime-0.1.1.tgz", + "integrity": "sha512-QsgMjOu5BZKcCPOSZVP32bqHjL1YeUNlarzygqZkMpKK89yZTpqYvrG2VGIUOLj3ESvkn0Cr+D7OlzsE8ZayOA==", + "requires": { + "swr": "^1.3.0" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "aria-query": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.10.2", + "@babel/runtime-corejs3": "^7.10.2" + } + }, + "array-includes": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.5.tgz", + "integrity": "sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "array.prototype.flat": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.0.tgz", + "integrity": "sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + } + }, + "array.prototype.flatmap": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.0.tgz", + "integrity": "sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.2", + "es-shim-unscopables": "^1.0.0" + } + }, + "ast-types-flow": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz", + "integrity": "sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==", + "dev": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, + "autoprefixer": { + "version": "10.4.12", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.12.tgz", + "integrity": "sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==", + "requires": { + "browserslist": "^4.21.4", + "caniuse-lite": "^1.0.30001407", + "fraction.js": "^4.2.0", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "axe-core": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz", + "integrity": "sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==", + "dev": true + }, + "axobject-query": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.2.0.tgz", + "integrity": "sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.21.4", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.4.tgz", + "integrity": "sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==", + "requires": { + "caniuse-lite": "^1.0.30001400", + "electron-to-chromium": "^1.4.251", + "node-releases": "^2.0.6", + "update-browserslist-db": "^1.0.9" + } + }, + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" + }, + "caniuse-lite": { + "version": "1.0.30001415", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001415.tgz", + "integrity": "sha512-ER+PfgCJUe8BqunLGWd/1EY4g8AzQcsDAVzdtMGKVtQEmKAwaFfU6vb7EAVIqTMYsqxBorYZi2+22Iouj/y7GQ==" + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "color": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", + "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", + "requires": { + "color-convert": "^2.0.1", + "color-string": "^1.9.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "cookie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" + }, + "core-js-pure": { + "version": "3.25.5", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.25.5.tgz", + "integrity": "sha512-oml3M22pHM+igfWHDfdLVq2ShWmjM2V4L+dQEBs0DWVIqEm9WHCwGAlZ6BmyBQGy5sFrJmcx+856D9lVKyGWYg==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "css-selector-tokenizer": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz", + "integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==", + "requires": { + "cssesc": "^3.0.0", + "fastparse": "^1.1.2" + } + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==", + "dev": true + }, + "daisyui": { + "version": "2.31.0", + "resolved": "https://registry.npmjs.org/daisyui/-/daisyui-2.31.0.tgz", + "integrity": "sha512-qepRXgQPLNcJ8ZPZy+dUvsC7mRWvMLRcVMe85/wZA60Tnhm/bkidhOzdllL8aAk2JX+W/xlIsTJ8NZFpPm+eyw==", + "requires": { + "color": "^4.2", + "css-selector-tokenizer": "^0.8.0", + "postcss-js": "^4.0.0", + "tailwindcss": "^3" + } + }, + "damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "define-properties": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", + "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", + "dev": true, + "requires": { + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==" + }, + "detective": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz", + "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==", + "requires": { + "acorn-node": "^1.8.2", + "defined": "^1.0.0", + "minimist": "^1.2.6" + } + }, + "didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==" + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "electron-to-chromium": { + "version": "1.4.271", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.271.tgz", + "integrity": "sha512-BCPBtK07xR1/uY2HFDtl3wK2De66AW4MSiPlLrnPNxKC/Qhccxd59W73654S3y6Rb/k3hmuGJOBnhjfoutetXA==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "es-abstract": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.3.tgz", + "integrity": "sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "function.prototype.name": "^1.1.5", + "get-intrinsic": "^1.1.3", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-property-descriptors": "^1.0.0", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.6", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-weakref": "^1.0.2", + "object-inspect": "^1.12.2", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.4.3", + "safe-regex-test": "^1.0.0", + "string.prototype.trimend": "^1.0.5", + "string.prototype.trimstart": "^1.0.5", + "unbox-primitive": "^1.0.2" + } + }, + "es-shim-unscopables": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.0.tgz", + "integrity": "sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "7.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.32.0.tgz", + "integrity": "sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.3", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + } + }, + "eslint-config-next": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-12.3.1.tgz", + "integrity": "sha512-EN/xwKPU6jz1G0Qi6Bd/BqMnHLyRAL0VsaQaWA7F3KkjAgZHi4f1uL1JKGWNxdQpHTW/sdGONBd0bzxUka/DJg==", + "dev": true, + "requires": { + "@next/eslint-plugin-next": "12.3.1", + "@rushstack/eslint-patch": "^1.1.3", + "@typescript-eslint/parser": "^5.21.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^2.7.1", + "eslint-plugin-import": "^2.26.0", + "eslint-plugin-jsx-a11y": "^6.5.1", + "eslint-plugin-react": "^7.31.7", + "eslint-plugin-react-hooks": "^4.5.0" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-import-resolver-typescript": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-2.7.1.tgz", + "integrity": "sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "glob": "^7.2.0", + "is-glob": "^4.0.3", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "eslint-module-utils": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.4.tgz", + "integrity": "sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==", + "dev": true, + "requires": { + "debug": "^3.2.7" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.26.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", + "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.3", + "has": "^1.0.3", + "is-core-module": "^2.8.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.values": "^1.1.5", + "resolve": "^1.22.0", + "tsconfig-paths": "^3.14.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + } + } + }, + "eslint-plugin-jsx-a11y": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.6.1.tgz", + "integrity": "sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==", + "dev": true, + "requires": { + "@babel/runtime": "^7.18.9", + "aria-query": "^4.2.2", + "array-includes": "^3.1.5", + "ast-types-flow": "^0.0.7", + "axe-core": "^4.4.3", + "axobject-query": "^2.2.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "has": "^1.0.3", + "jsx-ast-utils": "^3.3.2", + "language-tags": "^1.0.5", + "minimatch": "^3.1.2", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-plugin-react": { + "version": "7.31.8", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", + "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==", + "dev": true, + "requires": { + "array-includes": "^3.1.5", + "array.prototype.flatmap": "^1.3.0", + "doctrine": "^2.1.0", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.5", + "object.fromentries": "^2.0.5", + "object.hasown": "^1.1.1", + "object.values": "^1.1.5", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.3", + "semver": "^6.3.0", + "string.prototype.matchall": "^4.0.7" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "resolve": { + "version": "2.0.0-next.4", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.4.tgz", + "integrity": "sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "requires": {} + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "dependencies": { + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastparse": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz", + "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==" + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "fraction.js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.0.tgz", + "integrity": "sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "function.prototype.name": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.5.tgz", + "integrity": "sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0", + "functions-have-names": "^1.2.2" + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==", + "dev": true + }, + "functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", + "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "13.17.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz", + "integrity": "sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "dependencies": { + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", + "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.1" + } + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true + }, + "is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "jose": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-4.10.0.tgz", + "integrity": "sha512-KEhB/eLGLomWGPTb+/RNbYsTjIyx03JmbqAyIyiXBuNSa7CmNrJd5ysFhblayzs/e/vbOPMUaLnjHUMhGp4yLw==" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsx-ast-utils": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", + "integrity": "sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==", + "dev": true, + "requires": { + "array-includes": "^3.1.5", + "object.assign": "^4.1.3" + } + }, + "language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "language-tags": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.5.tgz", + "integrity": "sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==", + "dev": true, + "requires": { + "language-subtag-registry": "~0.3.2" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lilconfig": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.6.tgz", + "integrity": "sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "next": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/next/-/next-12.3.1.tgz", + "integrity": "sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==", + "requires": { + "@next/env": "12.3.1", + "@next/swc-android-arm-eabi": "12.3.1", + "@next/swc-android-arm64": "12.3.1", + "@next/swc-darwin-arm64": "12.3.1", + "@next/swc-darwin-x64": "12.3.1", + "@next/swc-freebsd-x64": "12.3.1", + "@next/swc-linux-arm-gnueabihf": "12.3.1", + "@next/swc-linux-arm64-gnu": "12.3.1", + "@next/swc-linux-arm64-musl": "12.3.1", + "@next/swc-linux-x64-gnu": "12.3.1", + "@next/swc-linux-x64-musl": "12.3.1", + "@next/swc-win32-arm64-msvc": "12.3.1", + "@next/swc-win32-ia32-msvc": "12.3.1", + "@next/swc-win32-x64-msvc": "12.3.1", + "@swc/helpers": "0.4.11", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.0.7", + "use-sync-external-store": "1.2.0" + }, + "dependencies": { + "postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + } + } + }, + "next-auth": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.12.2.tgz", + "integrity": "sha512-B25iFUIKYa2pRMWRFPIQWv84WJydqIsv6EbriNuzqNSZnxnlmpsrmJrTeMMLf+9a3qf9FG8enxDmDntmwnBkDQ==", + "requires": { + "@babel/runtime": "^7.16.3", + "@panva/hkdf": "^1.0.1", + "cookie": "^0.5.0", + "jose": "^4.9.3", + "oauth": "^0.9.15", + "openid-client": "^5.1.0", + "preact": "^10.6.3", + "preact-render-to-string": "^5.1.19", + "uuid": "^8.3.2" + } + }, + "node-releases": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", + "integrity": "sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==" + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" + }, + "oauth": { + "version": "0.9.15", + "resolved": "https://registry.npmjs.org/oauth/-/oauth-0.9.15.tgz", + "integrity": "sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true + }, + "object-hash": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz", + "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==" + }, + "object-inspect": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz", + "integrity": "sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.4.tgz", + "integrity": "sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + } + }, + "object.entries": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz", + "integrity": "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.fromentries": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz", + "integrity": "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "object.hasown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.1.tgz", + "integrity": "sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==", + "dev": true, + "requires": { + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, + "oidc-token-hash": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/oidc-token-hash/-/oidc-token-hash-5.0.1.tgz", + "integrity": "sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "openid-client": { + "version": "5.1.10", + "resolved": "https://registry.npmjs.org/openid-client/-/openid-client-5.1.10.tgz", + "integrity": "sha512-KYAtkxTuUwTvjAmH0QMFFP3i9l0+XhP2/blct6Q9kn+DUJ/lu8/g/bI8ghSgxz9dJLm/9cpB/1uLVGTcGGY0hw==", + "requires": { + "jose": "^4.1.4", + "lru-cache": "^6.0.0", + "object-hash": "^2.0.1", + "oidc-token-hash": "^5.0.1" + } + }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" + }, + "postcss": { + "version": "8.4.17", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz", + "integrity": "sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==", + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-import": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.1.0.tgz", + "integrity": "sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==", + "requires": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + } + }, + "postcss-js": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.0.tgz", + "integrity": "sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==", + "requires": { + "camelcase-css": "^2.0.1" + } + }, + "postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "requires": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + } + }, + "postcss-nested": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz", + "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==", + "requires": { + "postcss-selector-parser": "^6.0.6" + } + }, + "postcss-selector-parser": { + "version": "6.0.10", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz", + "integrity": "sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==", + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "preact": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.0.tgz", + "integrity": "sha512-Fk6+vB2kb6mSJfDgODq0YDhMfl0HNtK5+Uc9QqECO4nlyPAQwCI+BKyWO//idA7ikV7o+0Fm6LQmNuQi1wXI1w==" + }, + "preact-render-to-string": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.4.tgz", + "integrity": "sha512-iIPHb3BXUQ3Za6KNhkjN/waq11Oh+QWWtAgN3id3LrL+cszH3DYh8TxJPNQ6Aogsbu4JsqdJLBZltwPFpG6N6w==", + "requires": { + "pretty-format": "^3.8.0" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "pretty-format": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-3.8.0.tgz", + "integrity": "sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==" + }, + "prisma": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.4.0.tgz", + "integrity": "sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==", + "requires": { + "@prisma/engines": "4.4.0" + } + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "requires": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "requires": { + "pify": "^2.3.0" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, + "regexp.prototype.flags": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", + "integrity": "sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "functions-have-names": "^1.2.2" + } + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "safe-regex-test": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", + "integrity": "sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" + } + }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "requires": { + "loose-envify": "^1.1.0" + } + }, + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "requires": { + "is-arrayish": "^0.3.1" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + } + } + }, + "string.prototype.matchall": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", + "integrity": "sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.3", + "regexp.prototype.flags": "^1.4.1", + "side-channel": "^1.0.4" + } + }, + "string.prototype.trimend": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.5.tgz", + "integrity": "sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "string.prototype.trimstart": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.5.tgz", + "integrity": "sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.19.5" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "styled-jsx": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz", + "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==", + "requires": {} + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "swr": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/swr/-/swr-1.3.0.tgz", + "integrity": "sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==", + "requires": {} + }, + "table": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.8.0.tgz", + "integrity": "sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ajv": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.0.tgz", + "integrity": "sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "tailwindcss": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.1.8.tgz", + "integrity": "sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==", + "requires": { + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "color-name": "^1.1.4", + "detective": "^5.2.1", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "lilconfig": "^2.0.6", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.14", + "postcss-import": "^14.1.0", + "postcss-js": "^4.0.0", + "postcss-load-config": "^3.1.4", + "postcss-nested": "5.0.6", + "postcss-selector-parser": "^6.0.10", + "postcss-value-parser": "^4.2.0", + "quick-lru": "^5.1.1", + "resolve": "^1.22.1" + }, + "dependencies": { + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "requires": { + "is-glob": "^4.0.3" + } + }, + "object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==" + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "tsconfig-paths": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", + "integrity": "sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typescript": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.8.4.tgz", + "integrity": "sha512-QCh+85mCy+h0IGff8r5XWzOVSbBO+KfeYrMQh7NJ58QujwcE22u+NUSmUxqF+un70P9GXKxa2HCNiTTMJknyjQ==", + "dev": true + }, + "unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + } + }, + "update-browserslist-db": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", + "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "requires": {} + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + } + } +} diff --git a/samples/todo/package.json b/samples/todo/package.json index 0cc619fb8..ab0023bd2 100644 --- a/samples/todo/package.json +++ b/samples/todo/package.json @@ -10,13 +10,16 @@ "db-gen": "prisma generate --schema .zenstack/schema.prisma", "db-push": "prisma db push --schema .zenstack/schema.prisma", "db-migrate": "prisma migrate dev --schema .zenstack/schema.prisma", - "db-reset": "prisma migrate reset --schema .zenstack/schema.prisma" + "db-reset": "prisma migrate reset --schema .zenstack/schema.prisma", + "generate": "npm run --prefix ../../packages/schema build && node ../../packages/schema/bin/cli generate ./schema.zmodel --destination .zenstack" }, "dependencies": { - "@prisma/client": "^4.3.1", + "@prisma/client": "^4.4.0", + "@zenstackhq/runtime": "^0.1.1", "daisyui": "^2.31.0", "next": "12.3.1", "next-auth": "^4.10.3", + "prisma": "^4.4.0", "react": "18.2.0", "react-dom": "18.2.0", "swr": "^1.3.0" @@ -30,7 +33,6 @@ "eslint": "^7.19.0", "eslint-config-next": "12.3.1", "postcss": "^8.4.16", - "prisma": "^4.3.1", "tailwindcss": "^3.1.8", "typescript": "^4.6.2" } diff --git a/samples/todo/pages/api/auth/[...nextauth].ts b/samples/todo/pages/api/auth/[...nextauth].ts index 70334e68f..1c791fcc1 100644 --- a/samples/todo/pages/api/auth/[...nextauth].ts +++ b/samples/todo/pages/api/auth/[...nextauth].ts @@ -1,13 +1,13 @@ import NextAuth, { NextAuthOptions } from 'next-auth'; import CredentialsProvider from 'next-auth/providers/credentials'; import GoogleProvider from 'next-auth/providers/google'; -import { Authorize, NextAuthAdapter as Adapter } from '@zenstack/auth'; -import { client } from '@zenstack'; +import { authorize, NextAuthAdapter as Adapter } from '@zenstack/auth'; +import service from '@zenstack/service'; export const authOptions: NextAuthOptions = { // Configure one or more authentication providers - adapter: Adapter(client), + adapter: Adapter(service), session: { strategy: 'jwt', @@ -31,7 +31,7 @@ export const authOptions: NextAuthOptions = { placeholder: 'Your super secure password', }, }, - authorize: Authorize(client), + authorize: authorize(service), }), ], diff --git a/samples/todo/schema.zmodel b/samples/todo/schema.zmodel index 778b77842..1992233b7 100644 --- a/samples/todo/schema.zmodel +++ b/samples/todo/schema.zmodel @@ -13,7 +13,7 @@ enum SpaceUserRole { } model Space { - id String @id + id String @id @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt name String @length(1, 100) @@ -34,7 +34,7 @@ model Space { } model SpaceUser { - id String @id + id String @id @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt space Space @relation(fields:[spaceId], references: [id], onDelete: Cascade) @@ -56,15 +56,19 @@ model SpaceUser { } model User { - id String @id + id String @id @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt email String @unique @email + emailVerified DateTime? + password String name String? @length(1, 100) spaces SpaceUser[] image String? @url todoLists TodoList[] todos Todo[] + accounts Account[] + sessions Session[] // can be created by anyone, even not logged in @@allow('create', true) @@ -76,8 +80,42 @@ model User { @@allow('update,delete', auth() == this) } +model Account { + id String @id @default(uuid()) + userId String + type String + provider String + providerAccountId String + refresh_token String? + access_token String? + expires_at Int? + token_type String? + scope String? + id_token String? + session_state String? + user User @relation(fields: [userId], references: [id], onDelete: Cascade) + + @@unique([provider, providerAccountId]) +} + +model Session { + id String @id @default(uuid()) + sessionToken String @unique + userId String + expires DateTime + user User @relation(fields: [userId], references: [id], onDelete: Cascade) +} + +model VerificationToken { + identifier String + token String @unique + expires DateTime + + @@unique([identifier, token]) +} + model TodoList { - id String @id + id String @id @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt space Space @relation(fields: [spaceId], references: [id], onDelete: Cascade) @@ -99,7 +137,7 @@ model TodoList { } model Todo { - id String @id + id String @id @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) From 42bfa5bbe2e7d17ccff1dc8753c14ed78e03ac61 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Wed, 5 Oct 2022 23:00:37 +0800 Subject: [PATCH 04/15] structure for data/function generator --- packages/schema/src/cli/index.ts | 2 + packages/schema/src/generator/prisma/index.ts | 6 +- .../schema/src/generator/react-hooks/index.ts | 5 +- .../src/generator/server/data-generator.ts | 89 +++++++++++++++++++ .../generator/server/function-generator.ts | 29 ++++++ packages/schema/src/generator/server/index.ts | 54 +++++++++++ .../schema/src/generator/service/index.ts | 2 +- samples/todo/package-lock.json | 13 ++- samples/todo/package.json | 1 - samples/todo/pages/index.tsx | 13 --- 10 files changed, 190 insertions(+), 24 deletions(-) create mode 100644 packages/schema/src/generator/server/data-generator.ts create mode 100644 packages/schema/src/generator/server/function-generator.ts create mode 100644 packages/schema/src/generator/server/index.ts diff --git a/packages/schema/src/cli/index.ts b/packages/schema/src/cli/index.ts index c6c3a5c87..440f8635a 100644 --- a/packages/schema/src/cli/index.ts +++ b/packages/schema/src/cli/index.ts @@ -11,6 +11,7 @@ import PrismaGenerator from '../generator/prisma'; import ServiceGenerator from '../generator/service'; import ReactHooksGenerator from '../generator/react-hooks'; import NextAuthGenerator from '../generator/next-auth'; +import ServerGenerator from '../generator/server'; export const generateAction = async ( fileName: string, @@ -34,6 +35,7 @@ export const generateAction = async ( new PrismaGenerator(), new ServiceGenerator(), new ReactHooksGenerator(), + new ServerGenerator(), new NextAuthGenerator(), ]; diff --git a/packages/schema/src/generator/prisma/index.ts b/packages/schema/src/generator/prisma/index.ts index 32dee8d4a..7589d0dd3 100644 --- a/packages/schema/src/generator/prisma/index.ts +++ b/packages/schema/src/generator/prisma/index.ts @@ -75,7 +75,7 @@ export default class PrismaGenerator implements Generator { const outFile = path.join(context.outDir, 'schema.prisma'); await writeFile(outFile, prisma.toString()); - console.log(colors.blue(`Prisma schema generated`)); + console.log(colors.blue(` ✔️ Prisma schema generated`)); // run prisma generate and install @prisma/client await this.generatePrismaClient(outFile); @@ -86,11 +86,11 @@ export default class PrismaGenerator implements Generator { execSync('npx prisma'); } catch (err) { execSync(`npm i prisma @prisma/client`); - console.log(colors.blue('Prisma package installed')); + console.log(colors.blue(' ✔️ Prisma package installed')); } execSync(`npx prisma generate --schema "${schemaFile}"`); - console.log(colors.blue('Prisma client generated')); + console.log(colors.blue(' ✔️ Prisma client generated')); } private isStringLiteral(node: AstNode): node is LiteralExpr { diff --git a/packages/schema/src/generator/react-hooks/index.ts b/packages/schema/src/generator/react-hooks/index.ts index 38e2a0371..6e39e0f8a 100644 --- a/packages/schema/src/generator/react-hooks/index.ts +++ b/packages/schema/src/generator/react-hooks/index.ts @@ -23,7 +23,7 @@ export default class ReactHooksGenerator implements Generator { await project.save(); - console.log(colors.blue('React hooks generated')); + console.log(colors.blue(' ✔️ React hooks generated')); } private hasAllowRules(model: DataModel) { @@ -171,7 +171,6 @@ export default class ReactHooksGenerator implements Generator { useFuncBody .addFunction({ name: 'find', - isAsync: true, typeParameters: [`T extends P.${model.name}FindManyArgs`], parameters: [ { @@ -241,7 +240,7 @@ export default class ReactHooksGenerator implements Generator { parameters: [ { name: 'id', type: 'String' }, { - name: 'args', + name: 'args?', type: `Omit`, }, ], diff --git a/packages/schema/src/generator/server/data-generator.ts b/packages/schema/src/generator/server/data-generator.ts new file mode 100644 index 000000000..13b9ab3c5 --- /dev/null +++ b/packages/schema/src/generator/server/data-generator.ts @@ -0,0 +1,89 @@ +import { Context } from '../types'; +import { Project } from 'ts-morph'; +import { DataModel, isDataModel } from '../../language-server/generated/ast'; +import * as path from 'path'; +import { camelCase, paramCase } from 'change-case'; + +export default function generate(project: Project, context: Context) { + const models = context.schema.declarations.filter( + (d) => isDataModel(d) && hasAllowRules(d) + ) as DataModel[]; + + generateIndex(models, project, context); + models.forEach((model) => generateForModel(model, project, context)); +} + +function hasAllowRules(model: DataModel) { + return !!model.attributes.find((attr) => attr.decl.ref?.name === 'allow'); +} + +function generateIndex( + models: DataModel[], + project: Project, + context: Context +) { + const content = ` + import type { NextApiRequest, NextApiResponse } from 'next'; + import { RequestionHandlerOptions } from '..'; + ${models.map((model) => modelImport(model)).join('\n')} + + export default async function ( + req: NextApiRequest, + res: NextApiResponse, + path: string[], + options: RequestionHandlerOptions + ) { + const [type, ...rest] = path; + switch (type) { + ${models.map((model) => modelEntrance(model)).join('\n')} + default: + res.status(404).json({ error: 'Unknown type: ' + type }); + } + } + `; + const sf = project.createSourceFile( + path.join(context.outDir, 'server/data/index.ts'), + content, + { overwrite: true } + ); + sf.formatText(); +} + +function modelImport(model: DataModel) { + return `import ${camelCase(model.name)}Handler from './${paramCase( + model.name + )}';`; +} + +function modelEntrance(model: DataModel) { + return ` + case '${camelCase(model.name)}': + return ${camelCase(model.name)}Handler(req, res, rest, options); + `; +} + +function generateForModel( + model: DataModel, + project: Project, + context: Context +) { + const content = ` + import type { NextApiRequest, NextApiResponse } from 'next'; + import { RequestionHandlerOptions } from '..'; + + export default async function ( + req: NextApiRequest, + res: NextApiResponse, + path: string[], + options: RequestionHandlerOptions + ) { + throw new Error('Not implemented'); + } + `; + const sf = project.createSourceFile( + path.join(context.outDir, `server/data/${paramCase(model.name)}.ts`), + content, + { overwrite: true } + ); + sf.formatText(); +} diff --git a/packages/schema/src/generator/server/function-generator.ts b/packages/schema/src/generator/server/function-generator.ts new file mode 100644 index 000000000..6ccf83f5b --- /dev/null +++ b/packages/schema/src/generator/server/function-generator.ts @@ -0,0 +1,29 @@ +import { Context } from '../types'; +import { Project } from 'ts-morph'; +import * as path from 'path'; + +export default function generate(project: Project, context: Context) { + generateIndex(project, context); +} + +function generateIndex(project: Project, context: Context) { + const content = ` + import type { NextApiRequest, NextApiResponse } from 'next'; + import { RequestionHandlerOptions } from '..'; + + export default async function ( + req: NextApiRequest, + res: NextApiResponse, + path: string[], + options: RequestionHandlerOptions + ) { + throw new Error('Not implemented'); + } + `; + const sf = project.createSourceFile( + path.join(context.outDir, 'server/function/index.ts'), + content, + { overwrite: true } + ); + sf.formatText(); +} diff --git a/packages/schema/src/generator/server/index.ts b/packages/schema/src/generator/server/index.ts new file mode 100644 index 000000000..e144f7357 --- /dev/null +++ b/packages/schema/src/generator/server/index.ts @@ -0,0 +1,54 @@ +import { Project } from 'ts-morph'; +import { Context, Generator } from '../types'; +import * as path from 'path'; +import generateData from './data-generator'; +import generateFunction from './function-generator'; + +export default class DataServerGenerator implements Generator { + async generate(context: Context) { + const project = new Project(); + + this.generateIndex(project, context); + generateData(project, context); + generateFunction(project, context); + + await project.save(); + } + + generateIndex(project: Project, context: Context) { + const content = ` + import type { NextApiRequest, NextApiResponse } from 'next'; + import dataHandler from './data'; + import functionHandler from './function'; + + export type RequestionHandlerOptions = { + getServerUser: ( + req: NextApiRequest, + res: NextApiResponse + ) => Promise<{ id: string } | undefined>; + }; + + export function RequestHandler(options: RequestionHandlerOptions) { + return async (req: NextApiRequest, res: NextApiResponse) => { + const [route, ...rest] = req.query.path as string[]; + switch (route) { + case 'data': + return dataHandler(req, res, rest, options); + + case 'function': + return functionHandler(req, res, rest, options); + + default: + res.status(404).json({ error: 'Unknown route: ' + route }); + } + }; + } + `; + const sf = project.createSourceFile( + path.join(context.outDir, 'server/index.ts'), + content, + { overwrite: true } + ); + sf.formatText(); + } +} diff --git a/packages/schema/src/generator/service/index.ts b/packages/schema/src/generator/service/index.ts index 9d7ab4138..ce671d75c 100644 --- a/packages/schema/src/generator/service/index.ts +++ b/packages/schema/src/generator/service/index.ts @@ -38,6 +38,6 @@ export default class ServiceGenerator implements Generator { sf.formatText(); await project.save(); - console.log(colors.blue(`ZenStack service generated`)); + console.log(colors.blue(` ✔️ ZenStack service generated`)); } } diff --git a/samples/todo/package-lock.json b/samples/todo/package-lock.json index d994ee76f..49d8a8654 100644 --- a/samples/todo/package-lock.json +++ b/samples/todo/package-lock.json @@ -13,7 +13,6 @@ "daisyui": "^2.31.0", "next": "12.3.1", "next-auth": "^4.10.3", - "prisma": "^4.4.0", "react": "18.2.0", "react-dom": "18.2.0", "swr": "^1.3.0" @@ -471,7 +470,9 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.4.0.tgz", "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==", - "hasInstallScript": true + "hasInstallScript": true, + "optional": true, + "peer": true }, "node_modules/@prisma/engines-version": { "version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6", @@ -3186,6 +3187,8 @@ "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.4.0.tgz", "integrity": "sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==", "hasInstallScript": true, + "optional": true, + "peer": true, "dependencies": { "@prisma/engines": "4.4.0" }, @@ -4288,7 +4291,9 @@ "@prisma/engines": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.4.0.tgz", - "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==" + "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==", + "optional": true, + "peer": true }, "@prisma/engines-version": { "version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6", @@ -6217,6 +6222,8 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.4.0.tgz", "integrity": "sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==", + "optional": true, + "peer": true, "requires": { "@prisma/engines": "4.4.0" } diff --git a/samples/todo/package.json b/samples/todo/package.json index ab0023bd2..6305a6765 100644 --- a/samples/todo/package.json +++ b/samples/todo/package.json @@ -19,7 +19,6 @@ "daisyui": "^2.31.0", "next": "12.3.1", "next-auth": "^4.10.3", - "prisma": "^4.4.0", "react": "18.2.0", "react-dom": "18.2.0", "swr": "^1.3.0" diff --git a/samples/todo/pages/index.tsx b/samples/todo/pages/index.tsx index f8122b198..ba1726189 100644 --- a/samples/todo/pages/index.tsx +++ b/samples/todo/pages/index.tsx @@ -2,7 +2,6 @@ import type { NextPage } from 'next'; import LoginButton from '../components/LoginButton'; import { useSession } from 'next-auth/react'; import { useTodoList } from '@zenstack/hooks'; -import { inviteUser } from '@zenstack/functions'; import { SpaceUserRole, TodoList } from '@zenstack/.prisma'; const Home: NextPage = () => { @@ -43,14 +42,6 @@ const Home: NextPage = () => { await deleteTodoList(todoList.id); } - async function onInviteUser() { - await inviteUser( - 'f0c9fc5c-e6e5-4146-a540-214f6ac5701c', - 'dadd2e5b-d278-4695-8f6a-e6389bc109c0', - SpaceUserRole.ADMIN - ); - } - function renderTodoLists() { return ( <> @@ -91,10 +82,6 @@ const Home: NextPage = () => { Create Filled Todo List - -

Todo Lists

{renderTodoLists()} From 83ed319e5a556b3c08d974d18bc85d10c318f476 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Sat, 8 Oct 2022 16:50:26 +0800 Subject: [PATCH 05/15] WIP --- packages/schema/src/generator/prisma/index.ts | 13 +- .../src/generator/prisma/prisma-builder.ts | 24 +- .../schema/src/generator/react-hooks/index.ts | 16 +- .../src/generator/server/data-generator.ts | 262 +++++++++---- .../src/generator/server/expression-writer.ts | 355 ++++++++++++++++++ .../generator/server/function-generator.ts | 49 +-- packages/schema/src/generator/server/index.ts | 11 +- .../generator/server/server-code-generator.ts | 6 + packages/schema/src/generator/utils.ts | 13 + .../src/language-server/generated/ast.ts | 6 +- .../src/language-server/generated/grammar.ts | 165 +------- packages/schema/src/language-server/types.ts | 9 + .../src/language-server/zmodel-linker.ts | 25 +- .../schema/src/language-server/zmodel.langium | 34 +- .../tests/generator/expression-writer.test.ts | 264 +++++++++++++ .../{ => generator}/prisma-builder.test.ts | 2 +- .../schema/tests/{ => schema}/parser.test.ts | 187 ++++----- .../tests/{ => schema}/sample-todo.test.ts | 2 +- 18 files changed, 1037 insertions(+), 406 deletions(-) create mode 100644 packages/schema/src/generator/server/expression-writer.ts create mode 100644 packages/schema/src/generator/server/server-code-generator.ts create mode 100644 packages/schema/src/generator/utils.ts create mode 100644 packages/schema/src/language-server/types.ts create mode 100644 packages/schema/tests/generator/expression-writer.test.ts rename packages/schema/tests/{ => generator}/prisma-builder.test.ts (98%) rename packages/schema/tests/{ => schema}/parser.test.ts (74%) rename packages/schema/tests/{ => schema}/sample-todo.test.ts (87%) diff --git a/packages/schema/src/generator/prisma/index.ts b/packages/schema/src/generator/prisma/index.ts index 7589d0dd3..d21837376 100644 --- a/packages/schema/src/generator/prisma/index.ts +++ b/packages/schema/src/generator/prisma/index.ts @@ -182,7 +182,8 @@ export default class PrismaGenerator implements Generator { prisma.addGenerator( 'client', 'prisma-client-js', - path.join(context.outDir, '.prisma') + path.join(context.outDir, '.prisma'), + ['fieldReference'] ); } @@ -196,6 +197,16 @@ export default class PrismaGenerator implements Generator { this.generateModelField(model, field); } + // add an "zenstack_guard" field for dealing with pure auth() related conditions + model.addField('zenstack_guard', 'Boolean', [ + new PrismaFieldAttribute('default', [ + new PrismaAttributeArg( + undefined, + new PrismaAttributeArgValue('Boolean', true) + ), + ]), + ]); + for (const attr of decl.attributes.filter((attr) => supportedAttrbutes.includes(attr.decl.ref?.name!) )) { diff --git a/packages/schema/src/generator/prisma/prisma-builder.ts b/packages/schema/src/generator/prisma/prisma-builder.ts index efcb958a2..d8bfc8796 100644 --- a/packages/schema/src/generator/prisma/prisma-builder.ts +++ b/packages/schema/src/generator/prisma/prisma-builder.ts @@ -17,8 +17,18 @@ export class PrismaModel { return ds; } - addGenerator(name: string, provider: string, output: string) { - const generator = new Generator(name, provider, output); + addGenerator( + name: string, + provider: string, + output: string, + previewFeatures?: string[] + ) { + const generator = new Generator( + name, + provider, + output, + previewFeatures + ); this.generators.push(generator); return generator; } @@ -80,7 +90,8 @@ export class Generator { constructor( public name: string, public provider: string, - public output: string + public output: string, + public previewFeatures?: string[] ) {} toString() { @@ -88,6 +99,13 @@ export class Generator { `generator ${this.name} {\n` + indentString(`provider = "${this.provider}"\n`) + indentString(`output = "${this.output}"\n`) + + (this.previewFeatures + ? indentString( + `previewFeatures = [${this.previewFeatures + ?.map((f) => '"' + f + '"') + .join(',')}]\n` + ) + : '') + `}` ); } diff --git a/packages/schema/src/generator/react-hooks/index.ts b/packages/schema/src/generator/react-hooks/index.ts index 6e39e0f8a..d4a21d146 100644 --- a/packages/schema/src/generator/react-hooks/index.ts +++ b/packages/schema/src/generator/react-hooks/index.ts @@ -2,19 +2,15 @@ import { Context, Generator } from '../types'; import { Project } from 'ts-morph'; import * as path from 'path'; import { camelCase, paramCase } from 'change-case'; -import { DataModel, isDataModel } from '../../language-server/generated/ast'; +import { DataModel } from '../../language-server/generated/ast'; import colors from 'colors'; +import { extractDataModelsWithAllowRules } from '../utils'; export default class ReactHooksGenerator implements Generator { async generate(context: Context) { const project = new Project(); - const models = context.schema.declarations.filter( - (d) => - isDataModel(d) && - // only generate hooks if model has at least one @@allow rule - this.hasAllowRules(d) - ) as DataModel[]; + const models = extractDataModelsWithAllowRules(context.schema); this.generateIndex(project, context, models); this.generateRequestRuntime(project, context); @@ -26,12 +22,6 @@ export default class ReactHooksGenerator implements Generator { console.log(colors.blue(' ✔️ React hooks generated')); } - private hasAllowRules(model: DataModel) { - return !!model.attributes.find( - (attr) => attr.decl.ref?.name === 'allow' - ); - } - private generateRequestRuntime(project: Project, context: Context) { const content = ` import useSWR, { useSWRConfig } from 'swr'; diff --git a/packages/schema/src/generator/server/data-generator.ts b/packages/schema/src/generator/server/data-generator.ts index 13b9ab3c5..80b8100fb 100644 --- a/packages/schema/src/generator/server/data-generator.ts +++ b/packages/schema/src/generator/server/data-generator.ts @@ -1,89 +1,205 @@ import { Context } from '../types'; -import { Project } from 'ts-morph'; -import { DataModel, isDataModel } from '../../language-server/generated/ast'; +import { + CodeBlockWriter, + Project, + SourceFile, + VariableDeclarationKind, +} from 'ts-morph'; +import { DataModel, Expression } from '../../language-server/generated/ast'; import * as path from 'path'; import { camelCase, paramCase } from 'change-case'; +import { extractDataModelsWithAllowRules } from '../utils'; +import { ServerCodeGenerator } from './server-code-generator'; +import ExpressionWriter from './expression-writer'; -export default function generate(project: Project, context: Context) { - const models = context.schema.declarations.filter( - (d) => isDataModel(d) && hasAllowRules(d) - ) as DataModel[]; +export default class DataServerGenerator implements ServerCodeGenerator { + generate(project: Project, context: Context): void { + const models = extractDataModelsWithAllowRules(context.schema); + this.generateIndex(models, project, context); + models.forEach((model) => + this.generateForModel(model, project, context) + ); + } - generateIndex(models, project, context); - models.forEach((model) => generateForModel(model, project, context)); -} + private generateIndex( + models: DataModel[], + project: Project, + context: Context + ) { + const content = ` + import type { NextApiRequest, NextApiResponse } from 'next'; + import { RequestionHandlerOptions } from '..'; + ${models.map((model) => this.writeModelImport(model)).join('\n')} + + export default async private ( + req: NextApiRequest, + res: NextApiResponse, + path: string[], + options: RequestionHandlerOptions + ) { + const [type, ...rest] = path; + switch (type) { + ${models + .map((model) => this.writeModelEntrance(model)) + .join('\n')} + default: + res.status(404).json({ error: 'Unknown type: ' + type }); + } + } + `; + const sf = project.createSourceFile( + path.join(context.outDir, 'server/data/index.ts'), + content, + { overwrite: true } + ); + sf.formatText(); + } -function hasAllowRules(model: DataModel) { - return !!model.attributes.find((attr) => attr.decl.ref?.name === 'allow'); -} + private writeModelImport(model: DataModel) { + return `import ${camelCase(model.name)}Handler from './${paramCase( + model.name + )}';`; + } -function generateIndex( - models: DataModel[], - project: Project, - context: Context -) { - const content = ` - import type { NextApiRequest, NextApiResponse } from 'next'; - import { RequestionHandlerOptions } from '..'; - ${models.map((model) => modelImport(model)).join('\n')} - - export default async function ( - req: NextApiRequest, - res: NextApiResponse, - path: string[], - options: RequestionHandlerOptions + private writeModelEntrance(model: DataModel) { + return ` + case '${camelCase(model.name)}': + return ${camelCase(model.name)}Handler(req, res, rest, options); + `; + } + + private generateForModel( + model: DataModel, + project: Project, + context: Context ) { - const [type, ...rest] = path; - switch (type) { - ${models.map((model) => modelEntrance(model)).join('\n')} - default: - res.status(404).json({ error: 'Unknown type: ' + type }); + const content = ` + import type { NextApiRequest, NextApiResponse } from 'next'; + import { RequestionHandlerOptions } from '..'; + import service from '@zenstack/service'; + + export default async private ( + req: NextApiRequest, + res: NextApiResponse, + path: string[], + options: RequestionHandlerOptions + ) { + switch (req.method) { + case 'GET': + if (path.length > 0) { + return get(req, res, path[0], options); + } else { + return find(req, res, options); + } + + case 'POST': + return create(req, res, options); + + case 'PUT': + return update(req, res, path[0], options); + + case 'DELETE': + return del(req, res, path[0], options); + + default: + throw new Error('Unsupported HTTP method: ' + req.method); + } } + `; + const sf = project.createSourceFile( + path.join( + context.outDir, + `server/data/${paramCase(model.name)}.ts` + ), + content, + { overwrite: true } + ); + + this.generateFind(sf, model); + + sf.formatText(); } - `; - const sf = project.createSourceFile( - path.join(context.outDir, 'server/data/index.ts'), - content, - { overwrite: true } - ); - sf.formatText(); -} -function modelImport(model: DataModel) { - return `import ${camelCase(model.name)}Handler from './${paramCase( - model.name - )}';`; -} + private generateFind(sourceFile: SourceFile, model: DataModel) { + const func = sourceFile + .addFunction({ + name: 'find', + isAsync: true, + parameters: [ + { + name: 'req', + type: 'NextApiRequest', + }, + { + name: 'res', + type: 'NextApiResponse', + }, + { + name: 'options', + type: 'RequestionHandlerOptions', + }, + ], + }) + .addBody(); -function modelEntrance(model: DataModel) { - return ` - case '${camelCase(model.name)}': - return ${camelCase(model.name)}Handler(req, res, rest, options); - `; -} + func.addStatements([ + `const user = await getUser(req, res, options);`, + `const condition = req.query.q? (JSON.parse(req.query.q as string) as ${model.name}FindArgsInput): null;`, + ]); + + func.addVariableStatement({ + declarationKind: VariableDeclarationKind.Const, + declarations: [ + { + name: 'args', + type: 'TodoListFindArgsInput', + initializer: (writer) => this.writeFindArgs(writer, model), + }, + ], + }); + + func.addStatements([ + `res.status(200).send(await service.prisma.todoList.findMany(args));`, + ]); + } + + private writeFindArgs(writer: CodeBlockWriter, model: DataModel) { + writer.block(() => { + writer.writeLine('where:'); + writer.block(() => { + writer.indent(() => { + writer.writeLine('AND: ['); -function generateForModel( - model: DataModel, - project: Project, - context: Context -) { - const content = ` - import type { NextApiRequest, NextApiResponse } from 'next'; - import { RequestionHandlerOptions } from '..'; - - export default async function ( - req: NextApiRequest, - res: NextApiResponse, - path: string[], - options: RequestionHandlerOptions + this.writeDenyRules(writer, model); + this.writeAllowRules(writer, model); + + writer.writeLine(']'); + }); + }); + }); + } + + private writeDenyRules(writer: CodeBlockWriter, model: DataModel) { + const attrs = model.attributes.filter( + (attr) => attr.args.length > 0 && attr.decl.ref?.name === 'deny' + ); + attrs.forEach((attr) => + this.writeDenyRule(writer, model, attr.args[0].value) + ); + } + + private writeDenyRule( + writer: CodeBlockWriter, + model: DataModel, + rule: Expression ) { - throw new Error('Not implemented'); + writer.block(() => { + writer.writeLine('NOT: '); + new ExpressionWriter(writer).write(rule); + }); + } + + private writeAllowRules(writer: CodeBlockWriter, model: DataModel) { + // throw new Error('private not implemented.'); } - `; - const sf = project.createSourceFile( - path.join(context.outDir, `server/data/${paramCase(model.name)}.ts`), - content, - { overwrite: true } - ); - sf.formatText(); } diff --git a/packages/schema/src/generator/server/expression-writer.ts b/packages/schema/src/generator/server/expression-writer.ts new file mode 100644 index 000000000..0a1df2691 --- /dev/null +++ b/packages/schema/src/generator/server/expression-writer.ts @@ -0,0 +1,355 @@ +import { + ArrayExpr, + BinaryExpr, + Expression, + InvocationExpr, + isDataModel, + isDataModelField, + isMemberAccessExpr, + isReferenceExpr, + LiteralExpr, + MemberAccessExpr, + NullExpr, + ReferenceExpr, + ThisExpr, + UnaryExpr, +} from '../../language-server/generated/ast'; +import { CodeBlockWriter } from 'ts-morph'; +import { GeneratorError } from '../types'; +import { TypedNode } from 'language-server/types'; + +const AUX_GUARD_FIELD = 'zenstack_guard'; + +type Context = { + nested: boolean; +}; + +type ComparisonOperator = '==' | '!=' | '>' | '>=' | '<' | '<='; + +export default class ExpressionWriter { + constructor(private readonly writer: CodeBlockWriter) {} + + write(expr: Expression, context: Context = { nested: false }) { + const _write = () => { + switch (expr.$type) { + case LiteralExpr: + this.writeLiteral(expr as LiteralExpr, context); + break; + + case UnaryExpr: + this.writeUnary(expr as UnaryExpr, context); + break; + + case BinaryExpr: + this.writeBinary(expr as BinaryExpr, context); + break; + + case ReferenceExpr: + this.writeReference(expr as ReferenceExpr, context); + break; + + case InvocationExpr: + this.writeInvocation(expr as InvocationExpr, context); + break; + + case MemberAccessExpr: + this.writeMemberAccess(expr as MemberAccessExpr, context); + break; + + case ArrayExpr: + throw new Error('Not implemented'); + + case NullExpr: + this.writeNull(context); + break; + + case ThisExpr: + throw new Error('Not implemented'); + + default: + throw new Error(`Not implemented: ${expr.$type}`); + } + }; + + if (context.nested) { + _write(); + } else { + this.writer.block(_write); + } + } + + private writeReference(expr: ReferenceExpr, context: Context) { + if (!isDataModelField(expr.target.ref)) { + throw new GeneratorError('must be a field in current model'); + } + this.writer.write(`${expr.target.ref.name}: true`); + } + + private writeMemberAccess(expr: MemberAccessExpr, context: Context) { + this.write(expr.operand, context); + this.writer.write('.' + expr.member.ref?.name); + } + + private writeNull(context: Context) { + this.writer.write('null'); + } + + private writeInvocation(expr: InvocationExpr, context: Context) { + if (expr.function.ref?.name !== 'auth') { + throw new GeneratorError( + `Function invocation is not supported: ${expr.function.ref?.name}` + ); + } + + this.writer.write('user'); + } + + private writeExprList(exprs: Expression[], context: Context) { + this.writer.writeLine('['); + for (let i = 0; i < exprs.length; i++) { + this.write(exprs[i], context); + if (i !== exprs.length - 1) { + this.writer.writeLine(','); + } + } + this.writer.writeLine(']'); + } + + private writeBinary(expr: BinaryExpr, context: Context) { + switch (expr.operator) { + case '&&': + case '||': + this.writeLogical(expr, expr.operator, context); + break; + + case '==': + case '!=': + case '>': + case '>=': + case '<': + case '<=': + this.writeComparison(expr, expr.operator, context); + break; + } + } + + private isFieldRef(expr: Expression): expr is ReferenceExpr { + if (isReferenceExpr(expr) && isDataModelField(expr.target.ref)) { + return true; + } else { + return false; + } + } + + private guard(write: () => void) { + this.writer.write(`${AUX_GUARD_FIELD}: `); + write(); + } + + private quote(write: () => void) { + this.writer.write('('); + write(); + this.writer.write(')'); + } + + private writeComparison( + expr: BinaryExpr, + operator: ComparisonOperator, + context: Context + ) { + const leftIsFieldAccess = + this.isFieldRef(expr.left) || this.isRelationFieldAccess(expr.left); + const rightIsFieldAccess = + this.isFieldRef(expr.right) || + this.isRelationFieldAccess(expr.right); + + if (leftIsFieldAccess && rightIsFieldAccess) { + throw new GeneratorError( + `Comparison between fields are not supported yet` + ); + } + + if (!leftIsFieldAccess && !rightIsFieldAccess) { + // compile down to a plain expression + const newContext = { ...context, nested: true }; + this.guard(() => { + this.write(expr.left, newContext); + this.writer.write(' ' + operator + ' '); + this.write(expr.right, newContext); + }); + return; + } + + let fieldAccess: Expression; + let operand: Expression; + if (leftIsFieldAccess) { + fieldAccess = expr.left; + operand = expr.right; + } else { + fieldAccess = expr.right; + operand = expr.left; + operator = this.negateOperator(operator); + } + + const type = (fieldAccess as TypedNode).$resolvedType?.decl; + + this.writeFieldCondition(fieldAccess, () => { + this.writer.block(() => { + if (isDataModel(type)) { + // comparing with an object, conver to "id" comparison instead + this.writer.write('id: '); + this.writer.block(() => { + this.writeOperator(operator, () => { + this.write(operand, { ...context, nested: true }); + this.writer.write('.id'); + }); + }); + } else { + this.writeOperator(operator, () => { + this.write(operand, { ...context, nested: true }); + }); + } + }); + }); + } + + private writeOperator( + operator: ComparisonOperator, + writeOperand: () => void + ) { + if (operator === '!=') { + // wrap a 'not' + this.writer.write('not: '); + this.writer.block(() => { + this.writeOperator('==', writeOperand); + }); + } else { + this.writer.write(`${this.mapOperator(operator)}: `); + writeOperand(); + } + } + + private writeFieldCondition( + fieldAccess: Expression, + writeCondition: () => void + ) { + if (isReferenceExpr(fieldAccess)) { + if (this.isRelationFieldAccess(fieldAccess)) { + this.writer.write(fieldAccess.target.ref?.name! + ': '); + this.writer.block(() => { + this.writer.write('is: '); + writeCondition(); + }); + } else { + this.writer.write(fieldAccess.target.ref?.name! + ': '); + writeCondition(); + } + } else if (isMemberAccessExpr(fieldAccess)) { + this.writeFieldCondition(fieldAccess.operand, () => { + this.writer.block(() => { + this.writer.write(fieldAccess.member.ref?.name! + ': '); + writeCondition(); + }); + }); + } else { + throw new GeneratorError( + `Unsupported expression type: ${fieldAccess.$type}` + ); + } + } + + private isRelationFieldAccess(expr: Expression): boolean { + if (isMemberAccessExpr(expr)) { + return this.isRelationFieldAccess(expr.operand); + } + + if ( + isReferenceExpr(expr) && + isDataModelField(expr.target.ref) && + expr.target.ref.type.reference && + isDataModel(expr.target.ref.type.reference.ref) + ) { + return true; + } + + return false; + } + + mapOperator(operator: '==' | '!=' | '>' | '>=' | '<' | '<=') { + switch (operator) { + case '==': + return 'equals'; + case '!=': + // TODO + return 'not_equal'; + case '>': + return 'gt'; + case '>=': + return 'ge'; + case '<': + return 'lt'; + case '<=': + return 'le'; + } + } + + private negateOperator(operator: '==' | '!=' | '>' | '>=' | '<' | '<=') { + switch (operator) { + case '>': + return '<='; + case '<': + return '>='; + case '>=': + return '<'; + case '<=': + return '>'; + default: + return operator; + } + } + + private writeLogical( + expr: BinaryExpr, + operator: '&&' | '||', + context: Context + ) { + if (context.nested) { + this.quote(() => this.write(expr.left, context)); + this.writer.write(operator); + this.quote(() => this.write(expr.right, context)); + } else { + this.writer.writeLine(`${operator === '&&' ? 'AND' : 'OR'}: `); + this.writeExprList([expr.left, expr.right], context); + } + } + + private writeUnary(expr: UnaryExpr, context: Context) { + if (expr.operator !== '!') { + throw new GeneratorError( + `Unary operator "${expr.operator}" is not supported` + ); + } + + if (context.nested) { + this.writer.write(expr.operator); + this.quote(() => this.write(expr.operand, context)); + } else { + this.writer.writeLine('NOT: '); + this.write(expr.operand, context); + } + } + + private writeLiteral(expr: LiteralExpr, context: Context) { + if (context.nested) { + if (typeof expr.value === 'string') { + this.writer.write(`'${expr.value.toString()}'`); + } else { + this.writer.write(expr.value.toString()); + } + } else { + this.guard(() => { + this.writer.write(expr.value.toString()); + }); + } + } +} diff --git a/packages/schema/src/generator/server/function-generator.ts b/packages/schema/src/generator/server/function-generator.ts index 6ccf83f5b..92681ccc8 100644 --- a/packages/schema/src/generator/server/function-generator.ts +++ b/packages/schema/src/generator/server/function-generator.ts @@ -1,29 +1,32 @@ import { Context } from '../types'; import { Project } from 'ts-morph'; import * as path from 'path'; +import { ServerCodeGenerator } from './server-code-generator'; -export default function generate(project: Project, context: Context) { - generateIndex(project, context); -} +export default class FunctionServerGenerator implements ServerCodeGenerator { + generate(project: Project, context: Context) { + this.generateIndex(project, context); + } -function generateIndex(project: Project, context: Context) { - const content = ` - import type { NextApiRequest, NextApiResponse } from 'next'; - import { RequestionHandlerOptions } from '..'; - - export default async function ( - req: NextApiRequest, - res: NextApiResponse, - path: string[], - options: RequestionHandlerOptions - ) { - throw new Error('Not implemented'); - } - `; - const sf = project.createSourceFile( - path.join(context.outDir, 'server/function/index.ts'), - content, - { overwrite: true } - ); - sf.formatText(); + private generateIndex(project: Project, context: Context) { + const content = ` + import type { NextApiRequest, NextApiResponse } from 'next'; + import { RequestionHandlerOptions } from '..'; + + export default async function ( + req: NextApiRequest, + res: NextApiResponse, + path: string[], + options: RequestionHandlerOptions + ) { + throw new Error('Not implemented'); + } + `; + const sf = project.createSourceFile( + path.join(context.outDir, 'server/function/index.ts'), + content, + { overwrite: true } + ); + sf.formatText(); + } } diff --git a/packages/schema/src/generator/server/index.ts b/packages/schema/src/generator/server/index.ts index e144f7357..8ae354a53 100644 --- a/packages/schema/src/generator/server/index.ts +++ b/packages/schema/src/generator/server/index.ts @@ -1,16 +1,17 @@ import { Project } from 'ts-morph'; import { Context, Generator } from '../types'; import * as path from 'path'; -import generateData from './data-generator'; -import generateFunction from './function-generator'; +import DataServerGenerator from './data-generator'; +import FunctionServerGenerator from './function-generator'; -export default class DataServerGenerator implements Generator { +export default class ServerGenerator implements Generator { async generate(context: Context) { const project = new Project(); this.generateIndex(project, context); - generateData(project, context); - generateFunction(project, context); + + new DataServerGenerator().generate(project, context); + new FunctionServerGenerator().generate(project, context); await project.save(); } diff --git a/packages/schema/src/generator/server/server-code-generator.ts b/packages/schema/src/generator/server/server-code-generator.ts new file mode 100644 index 000000000..7849be772 --- /dev/null +++ b/packages/schema/src/generator/server/server-code-generator.ts @@ -0,0 +1,6 @@ +import { Context } from '../types'; +import { Project } from 'ts-morph'; + +export interface ServerCodeGenerator { + generate(project: Project, context: Context): void; +} diff --git a/packages/schema/src/generator/utils.ts b/packages/schema/src/generator/utils.ts new file mode 100644 index 000000000..580f6dbfe --- /dev/null +++ b/packages/schema/src/generator/utils.ts @@ -0,0 +1,13 @@ +import { + DataModel, + isDataModel, + Model, +} from '../language-server/generated/ast'; + +export function extractDataModelsWithAllowRules(model: Model) { + return model.declarations.filter( + (d) => + isDataModel(d) && + !!d.attributes.find((attr) => attr.decl.ref?.name === 'allow') + ) as DataModel[]; +} diff --git a/packages/schema/src/language-server/generated/ast.ts b/packages/schema/src/language-server/generated/ast.ts index edd0b2658..3629f1800 100644 --- a/packages/schema/src/language-server/generated/ast.ts +++ b/packages/schema/src/language-server/generated/ast.ts @@ -115,7 +115,7 @@ export function isAttributeParamType(item: unknown): item is AttributeParamType export interface BinaryExpr extends AstNode { readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; left: Expression - operator: '!' | '!=' | '&&' | '*' | '+' | '-' | '/' | '<' | '<=' | '==' | '>' | '>=' | '?' | '||' + operator: '!' | '!=' | '&&' | '<' | '<=' | '==' | '>' | '>=' | '?' | '||' right: Expression } @@ -368,8 +368,8 @@ export function isThisExpr(item: unknown): item is ThisExpr { export interface UnaryExpr extends AstNode { readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; - arg: Expression - operator: '!' | '+' | '-' + operand: Expression + operator: '!' } export const UnaryExpr = 'UnaryExpr'; diff --git a/packages/schema/src/language-server/generated/grammar.ts b/packages/schema/src/language-server/generated/grammar.ts index f4df248bf..51c47a6b4 100644 --- a/packages/schema/src/language-server/generated/grammar.ts +++ b/packages/schema/src/language-server/generated/grammar.ts @@ -560,26 +560,13 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "feature": "operator", "operator": "=", "terminal": { - "$type": "Alternatives", - "elements": [ - { - "$type": "Keyword", - "value": "+" - }, - { - "$type": "Keyword", - "value": "-" - }, - { - "$type": "Keyword", - "value": "!" - } - ] + "$type": "Keyword", + "value": "!" } }, { "$type": "Assignment", - "feature": "arg", + "feature": "operand", "operator": "=", "terminal": { "$type": "RuleCall", @@ -739,148 +726,6 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "parameters": [], "wildcard": false }, - { - "$type": "ParserRule", - "name": "MultDivExpr", - "inferredType": { - "$type": "InferredType", - "name": "Expression" - }, - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "RuleCall", - "rule": { - "$refText": "CollectionPredicateExpr" - }, - "arguments": [] - }, - { - "$type": "Group", - "elements": [ - { - "$type": "Action", - "inferredType": { - "$type": "InferredType", - "name": "BinaryExpr" - }, - "feature": "left", - "operator": "=" - }, - { - "$type": "Assignment", - "feature": "operator", - "operator": "=", - "terminal": { - "$type": "Alternatives", - "elements": [ - { - "$type": "Keyword", - "value": "*" - }, - { - "$type": "Keyword", - "value": "/" - } - ] - } - }, - { - "$type": "Assignment", - "feature": "right", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "CollectionPredicateExpr" - }, - "arguments": [] - } - } - ], - "cardinality": "*" - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, - { - "$type": "ParserRule", - "name": "AddSubExpr", - "inferredType": { - "$type": "InferredType", - "name": "Expression" - }, - "alternatives": { - "$type": "Group", - "elements": [ - { - "$type": "RuleCall", - "rule": { - "$refText": "MultDivExpr" - }, - "arguments": [] - }, - { - "$type": "Group", - "elements": [ - { - "$type": "Action", - "inferredType": { - "$type": "InferredType", - "name": "BinaryExpr" - }, - "feature": "left", - "operator": "=" - }, - { - "$type": "Assignment", - "feature": "operator", - "operator": "=", - "terminal": { - "$type": "Alternatives", - "elements": [ - { - "$type": "Keyword", - "value": "+" - }, - { - "$type": "Keyword", - "value": "-" - } - ] - } - }, - { - "$type": "Assignment", - "feature": "right", - "operator": "=", - "terminal": { - "$type": "RuleCall", - "rule": { - "$refText": "MultDivExpr" - }, - "arguments": [] - } - } - ], - "cardinality": "*" - } - ] - }, - "definesHiddenTokens": false, - "entry": false, - "fragment": false, - "hiddenTokens": [], - "parameters": [], - "wildcard": false - }, { "$type": "ParserRule", "name": "ComparisonExpr", @@ -894,7 +739,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG { "$type": "RuleCall", "rule": { - "$refText": "AddSubExpr" + "$refText": "CollectionPredicateExpr" }, "arguments": [] }, @@ -943,7 +788,7 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG "terminal": { "$type": "RuleCall", "rule": { - "$refText": "AddSubExpr" + "$refText": "CollectionPredicateExpr" }, "arguments": [] } diff --git a/packages/schema/src/language-server/types.ts b/packages/schema/src/language-server/types.ts new file mode 100644 index 000000000..950781b6c --- /dev/null +++ b/packages/schema/src/language-server/types.ts @@ -0,0 +1,9 @@ +import { AstNode } from 'langium'; +import { AbstractDeclaration } from './generated/ast'; + +export type TypedNode = AstNode & { + $resolvedType?: { + decl?: string | AbstractDeclaration; + array?: boolean; + }; +}; diff --git a/packages/schema/src/language-server/zmodel-linker.ts b/packages/schema/src/language-server/zmodel-linker.ts index ba19e67b4..9132841d4 100644 --- a/packages/schema/src/language-server/zmodel-linker.ts +++ b/packages/schema/src/language-server/zmodel-linker.ts @@ -34,19 +34,13 @@ import { ThisExpr, NullExpr, } from './generated/ast'; +import { TypedNode } from './types'; interface DefaultReference extends Reference { _ref?: AstNode | LinkingError; _nodeDescription?: AstNodeDescription; } -type TypedNode = AstNode & { - $resolvedType?: { - decl?: string | AbstractDeclaration; - array?: boolean; - }; -}; - type ScopeProvider = (name: string) => ReferenceTarget | undefined; export class ZModelLinker extends DefaultLinker { @@ -185,12 +179,13 @@ export class ZModelLinker extends DefaultLinker { this.resolve(node.left, document, extraScopes); this.resolve(node.right, document, extraScopes); switch (node.operator) { - case '+': - case '-': - case '*': - case '/': - this.resolveToBuiltinTypeOrDecl(node, 'Int'); - break; + // TODO: support arithmetics? + // case '+': + // case '-': + // case '*': + // case '/': + // this.resolveToBuiltinTypeOrDecl(node, 'Int'); + // break; case '>': case '>=': @@ -217,9 +212,9 @@ export class ZModelLinker extends DefaultLinker { document: LangiumDocument, extraScopes: ScopeProvider[] ) { - this.resolve(node.arg, document, extraScopes); + this.resolve(node.operand, document, extraScopes); (node as TypedNode).$resolvedType = ( - node.arg as TypedNode + node.operand as TypedNode ).$resolvedType; } diff --git a/packages/schema/src/language-server/zmodel.langium b/packages/schema/src/language-server/zmodel.langium index bff86413d..86f37a345 100644 --- a/packages/schema/src/language-server/zmodel.langium +++ b/packages/schema/src/language-server/zmodel.langium @@ -46,7 +46,7 @@ InvocationExpr: function=[Function] '(' ArgumentList? ')'; UnaryExpr: - operator=('+'|'-'|'!') arg=Expression; + operator=('!') operand=Expression; // binary operator precedence follow Javascript's rules: // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#table @@ -64,25 +64,27 @@ CollectionPredicateExpr infers Expression: '[' right=Expression ']' )*; -MultDivExpr infers Expression: - CollectionPredicateExpr ( - {infer BinaryExpr.left=current} - operator=('*'|'/') - right=CollectionPredicateExpr - )*; - -AddSubExpr infers Expression: - MultDivExpr ( - {infer BinaryExpr.left=current} - operator=('+'|'-') - right=MultDivExpr - )*; +// TODO: support arithmetics? +// +// MultDivExpr infers Expression: +// CollectionPredicateExpr ( +// {infer BinaryExpr.left=current} +// operator=('*'|'/') +// right=CollectionPredicateExpr +// )*; + +// AddSubExpr infers Expression: +// MultDivExpr ( +// {infer BinaryExpr.left=current} +// operator=('+'|'-') +// right=MultDivExpr +// )*; ComparisonExpr infers Expression: - AddSubExpr ( + CollectionPredicateExpr ( {infer BinaryExpr.left=current} operator=('>'|'<'|'>='|'<=') - right=AddSubExpr + right=CollectionPredicateExpr )*; EqualityExpr infers Expression: diff --git a/packages/schema/tests/generator/expression-writer.test.ts b/packages/schema/tests/generator/expression-writer.test.ts new file mode 100644 index 000000000..4bcfe031e --- /dev/null +++ b/packages/schema/tests/generator/expression-writer.test.ts @@ -0,0 +1,264 @@ +import { Project, VariableDeclarationKind } from 'ts-morph'; +import { + DataModel, + Expression, + isDataModel, +} from '../../src/language-server/generated/ast'; +import { loadModel } from '../utils'; +import * as tmp from 'tmp'; +import expressionWriter from '../../src/generator/server/expression-writer'; + +async function check( + schema: string, + getExpr: (model: DataModel) => Expression +) { + const model = await loadModel(schema); + const expr = getExpr( + model.declarations.find( + (d) => isDataModel(d) && d.name === 'Test' + ) as DataModel + ); + + const project = new Project(); + + const { name: sourcePath } = tmp.fileSync({ postfix: '.ts' }); + const sf = project.createSourceFile(sourcePath, undefined, { + overwrite: true, + }); + console.log(`Generated source: ${sourcePath}`); + + sf.addVariableStatement({ + declarationKind: VariableDeclarationKind.Const, + declarations: [{ name: 'user', initializer: '{ id: "user1" }' }], + }); + + sf.addVariableStatement({ + declarationKind: VariableDeclarationKind.Const, + declarations: [ + { + name: 'expr', + initializer: (writer) => + new expressionWriter(writer).write(expr), + }, + ], + }); + sf.formatText(); + + await project.save(); + + if (project.getPreEmitDiagnostics().length > 0) { + for (const d of project.getPreEmitDiagnostics()) { + console.warn(`${d.getLineNumber()}: ${d.getMessageText()}`); + } + throw new Error('Compilation errors occurred'); + } + + const outExpr = sf.getVariableDeclaration('expr'); + console.log('Generated expr:\n', outExpr?.getText()); + return outExpr?.getInitializer(); +} + +describe('Expression Writer Tests', () => { + it('boolean literal', async () => { + await check( + ` + model Test { + @@allow('all', true) + } + `, + (model) => model.attributes[0].args[1].value + ); + + await check( + ` + model Test { + @@allow('all', false) + } + `, + (model) => model.attributes[0].args[1].value + ); + }); + + it('boolean field', async () => { + await check( + ` + model Test { + flag Boolean + @@allow('all', flag) + } + `, + (model) => model.attributes[0].args[1].value + ); + + await check( + ` + model Test { + flag Boolean + @@allow('all', !flag) + } + `, + (model) => model.attributes[0].args[1].value + ); + }); + + it('field against literal', async () => { + await check( + ` + model Test { + count Int + @@allow('all', count > 0) + } + `, + (model) => model.attributes[0].args[1].value + ); + + await check( + ` + model Test { + label String + @@allow('all', label == 'thing') + } + `, + (model) => model.attributes[0].args[1].value + ); + }); + + it('logical', async () => { + await check( + ` + model Test { + count Int + @@allow('all', count > 0 && count > 1) + } + `, + (model) => model.attributes[0].args[1].value + ); + + await check( + ` + model Test { + count Int + @@allow('all', count > 0 || count > 1) + } + `, + (model) => model.attributes[0].args[1].value + ); + + await check( + ` + model Test { + count Int + @@allow('all', count > 0 && count > 1 || count > 2) + } + `, + (model) => model.attributes[0].args[1].value + ); + + await check( + ` + model Test { + count Int + @@allow('all', !(count > 0 && count > 1 || !count > 2)) + } + `, + (model) => model.attributes[0].args[1].value + ); + }); + + it('to-one relation query', async () => { + await check( + ` + model Foo { + count Int + } + + model Test { + foo Foo + @@deny(foo.count <= 0) + } + `, + (model) => model.attributes[0].args[0].value + ); + + await check( + ` + model Foo { + count Int + } + + model Test { + foo Foo + @@deny(!(foo.count > 0)) + } + `, + (model) => model.attributes[0].args[0].value + ); + }); + + it('auth check', async () => { + await check( + ` + model Test { + @@deny(auth() == null) + } + `, + (model) => model.attributes[0].args[0].value + ); + + await check( + ` + model Test { + @@allow('all', auth() != null) + } + `, + (model) => model.attributes[0].args[1].value + ); + }); + + it('auth check against field', async () => { + await check( + ` + model User { + id String @id + } + + model Test { + id String @id + owner User + @@allow('all', auth() == owner) + } + `, + (model) => model.attributes[0].args[1].value + ); + + await check( + ` + model User { + id String @id + } + + model Test { + id String @id + owner User + @@deny(auth() != owner) + } + `, + (model) => model.attributes[0].args[0].value + ); + + await check( + ` + model User { + id String @id + } + + model Test { + id String @id + owner User + @@allow('all', auth().id == owner.id) + } + `, + (model) => model.attributes[0].args[1].value + ); + }); +}); diff --git a/packages/schema/tests/prisma-builder.test.ts b/packages/schema/tests/generator/prisma-builder.test.ts similarity index 98% rename from packages/schema/tests/prisma-builder.test.ts rename to packages/schema/tests/generator/prisma-builder.test.ts index ad7550709..a420ba9e0 100644 --- a/packages/schema/tests/prisma-builder.test.ts +++ b/packages/schema/tests/generator/prisma-builder.test.ts @@ -8,7 +8,7 @@ import { ModelFieldType, FieldReference, FieldReferenceArg, -} from '../src/generator/prisma/prisma-builder'; +} from '../../src/generator/prisma/prisma-builder'; import { getDMMF } from '@prisma/internals'; async function validate(model: PrismaModel) { diff --git a/packages/schema/tests/parser.test.ts b/packages/schema/tests/schema/parser.test.ts similarity index 74% rename from packages/schema/tests/parser.test.ts rename to packages/schema/tests/schema/parser.test.ts index d4d4eada1..0aa16b783 100644 --- a/packages/schema/tests/parser.test.ts +++ b/packages/schema/tests/schema/parser.test.ts @@ -10,8 +10,8 @@ import { UnaryExpr, ReferenceExpr, ArrayExpr, -} from '../src/language-server/generated/ast'; -import { loadModel } from './utils'; +} from '../../src/language-server/generated/ast'; +import { loadModel } from '../utils'; describe('Basic Tests', () => { it('data source', async () => { @@ -194,7 +194,7 @@ describe('Basic Tests', () => { @@deny(!c) @@deny(a < 0) - @@deny(a + b < 10) + // @@deny(a + b < 10) } `; const doc = await loadModel(content); @@ -202,7 +202,7 @@ describe('Basic Tests', () => { const attrs = model.attributes; expect(attrs[0].args[0].value.$type).toBe(UnaryExpr); - expect((attrs[0].args[0].value as UnaryExpr).arg.$type).toBe( + expect((attrs[0].args[0].value as UnaryExpr).operand.$type).toBe( ReferenceExpr ); @@ -222,10 +222,10 @@ describe('Basic Tests', () => { LiteralExpr ); - expect(attrs[2].args[0].value.$type).toBe(BinaryExpr); - expect((attrs[2].args[0].value as BinaryExpr).left.$type).toBe( - BinaryExpr - ); + // expect(attrs[2].args[0].value.$type).toBe(BinaryExpr); + // expect((attrs[2].args[0].value as BinaryExpr).left.$type).toBe( + // BinaryExpr + // ); }); it('policy expression precedence', async () => { @@ -233,97 +233,100 @@ describe('Basic Tests', () => { model Model { a Int b Int - @@deny(a + b * 2 > 0) - @@deny((a + b) * 2 > 0) + // @@deny(a + b * 2 > 0) + // @@deny((a + b) * 2 > 0) @@deny(a > 0 && b < 0) @@deny(a >= 0 && b <= 0) @@deny(a == 0 || b != 0) } `; - const doc = await loadModel(content); - const attrs = (doc.declarations[0] as DataModel).attributes; - - expect(attrs[0].args[0].value.$type).toBe(BinaryExpr); - - // 1: a + b * 2 > 0 - - // > - expect((attrs[0].args[0].value as BinaryExpr).operator).toBe('>'); - - // a + b * 2 - expect((attrs[0].args[0].value as BinaryExpr).left.$type).toBe( - BinaryExpr - ); - - // 0 - expect((attrs[0].args[0].value as BinaryExpr).right.$type).toBe( - LiteralExpr - ); - - // + - expect( - ((attrs[0].args[0].value as BinaryExpr).left as BinaryExpr).operator - ).toBe('+'); - - // a - expect( - ((attrs[0].args[0].value as BinaryExpr).left as BinaryExpr).left - .$type - ).toBe(ReferenceExpr); - - // b * 2 - expect( - ((attrs[0].args[0].value as BinaryExpr).left as BinaryExpr).right - .$type - ).toBe(BinaryExpr); - - // 2: (a + b) * 2 > 0 - - // > - expect((attrs[1].args[0].value as BinaryExpr).operator).toBe('>'); - // (a + b) * 2 - expect((attrs[1].args[0].value as BinaryExpr).left.$type).toBe( - BinaryExpr - ); - - // 0 - expect((attrs[1].args[0].value as BinaryExpr).right.$type).toBe( - LiteralExpr - ); - - // * - expect( - ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr).operator - ).toBe('*'); - - // (a + b) - expect( - ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr).left - .$type - ).toBe(BinaryExpr); - - // a - expect( - ( - ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr) - .left as BinaryExpr - ).left.$type - ).toBe(ReferenceExpr); - - // b - expect( - ( - ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr) - .left as BinaryExpr - ).right.$type - ).toBe(ReferenceExpr); + await loadModel(content); - // 2 - expect( - ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr).right - .$type - ).toBe(LiteralExpr); + // const doc = await loadModel(content); + // const attrs = (doc.declarations[0] as DataModel).attributes; + + // expect(attrs[0].args[0].value.$type).toBe(BinaryExpr); + + // // 1: a + b * 2 > 0 + + // // > + // expect((attrs[0].args[0].value as BinaryExpr).operator).toBe('>'); + + // // a + b * 2 + // expect((attrs[0].args[0].value as BinaryExpr).left.$type).toBe( + // BinaryExpr + // ); + + // // 0 + // expect((attrs[0].args[0].value as BinaryExpr).right.$type).toBe( + // LiteralExpr + // ); + + // // + + // expect( + // ((attrs[0].args[0].value as BinaryExpr).left as BinaryExpr).operator + // ).toBe('+'); + + // // a + // expect( + // ((attrs[0].args[0].value as BinaryExpr).left as BinaryExpr).left + // .$type + // ).toBe(ReferenceExpr); + + // // b * 2 + // expect( + // ((attrs[0].args[0].value as BinaryExpr).left as BinaryExpr).right + // .$type + // ).toBe(BinaryExpr); + + // // 2: (a + b) * 2 > 0 + + // // > + // expect((attrs[1].args[0].value as BinaryExpr).operator).toBe('>'); + + // // (a + b) * 2 + // expect((attrs[1].args[0].value as BinaryExpr).left.$type).toBe( + // BinaryExpr + // ); + + // // 0 + // expect((attrs[1].args[0].value as BinaryExpr).right.$type).toBe( + // LiteralExpr + // ); + + // // * + // expect( + // ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr).operator + // ).toBe('*'); + + // // (a + b) + // expect( + // ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr).left + // .$type + // ).toBe(BinaryExpr); + + // // a + // expect( + // ( + // ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr) + // .left as BinaryExpr + // ).left.$type + // ).toBe(ReferenceExpr); + + // // b + // expect( + // ( + // ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr) + // .left as BinaryExpr + // ).right.$type + // ).toBe(ReferenceExpr); + + // // 2 + // expect( + // ((attrs[1].args[0].value as BinaryExpr).left as BinaryExpr).right + // .$type + // ).toBe(LiteralExpr); }); it('function', async () => { diff --git a/packages/schema/tests/sample-todo.test.ts b/packages/schema/tests/schema/sample-todo.test.ts similarity index 87% rename from packages/schema/tests/sample-todo.test.ts rename to packages/schema/tests/schema/sample-todo.test.ts index c9df1c8f4..c2c4e42e0 100644 --- a/packages/schema/tests/sample-todo.test.ts +++ b/packages/schema/tests/schema/sample-todo.test.ts @@ -1,4 +1,4 @@ -import { loadModel } from './utils'; +import { loadModel } from '../utils'; import * as fs from 'fs'; describe('Basic Tests', () => { From b52e9d41da79057bceee5dc64ce6c97267e7e145 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Sat, 8 Oct 2022 19:54:28 +0800 Subject: [PATCH 06/15] test cases --- .../src/generator/server/expression-writer.ts | 120 ++++-- .../src/language-server/generated/ast.ts | 2 +- .../src/language-server/generated/grammar.ts | 4 + .../src/language-server/zmodel-linker.ts | 2 + .../schema/src/language-server/zmodel.langium | 2 +- .../tests/generator/expression-writer.test.ts | 368 ++++++++++++++++-- 6 files changed, 429 insertions(+), 69 deletions(-) diff --git a/packages/schema/src/generator/server/expression-writer.ts b/packages/schema/src/generator/server/expression-writer.ts index 0a1df2691..aec71a67b 100644 --- a/packages/schema/src/generator/server/expression-writer.ts +++ b/packages/schema/src/generator/server/expression-writer.ts @@ -130,9 +130,29 @@ export default class ExpressionWriter { case '<=': this.writeComparison(expr, expr.operator, context); break; + + case '?': + case '!': + case '^': + this.writeCollectionPredicate(expr, expr.operator, context); + break; } } + private writeCollectionPredicate( + expr: BinaryExpr, + operator: string, + context: Context + ) { + this.writeFieldCondition( + expr.left, + () => { + this.write(expr.right, context); + }, + operator === '?' ? 'some' : operator === '!' ? 'every' : 'none' + ); + } + private isFieldRef(expr: Expression): expr is ReferenceExpr { if (isReferenceExpr(expr) && isDataModelField(expr.target.ref)) { return true; @@ -193,24 +213,31 @@ export default class ExpressionWriter { const type = (fieldAccess as TypedNode).$resolvedType?.decl; - this.writeFieldCondition(fieldAccess, () => { - this.writer.block(() => { - if (isDataModel(type)) { - // comparing with an object, conver to "id" comparison instead - this.writer.write('id: '); - this.writer.block(() => { + this.writeFieldCondition( + fieldAccess, + () => { + this.writer.block(() => { + if (isDataModel(type)) { + // comparing with an object, conver to "id" comparison instead + this.writer.write('id: '); + this.writer.block(() => { + this.writeOperator(operator, () => { + this.write(operand, { + ...context, + nested: true, + }); + this.writer.write('.id'); + }); + }); + } else { this.writeOperator(operator, () => { this.write(operand, { ...context, nested: true }); - this.writer.write('.id'); }); - }); - } else { - this.writeOperator(operator, () => { - this.write(operand, { ...context, nested: true }); - }); - } - }); - }); + } + }); + }, + 'is' + ); } private writeOperator( @@ -231,31 +258,60 @@ export default class ExpressionWriter { private writeFieldCondition( fieldAccess: Expression, - writeCondition: () => void + writeCondition: () => void, + relationOp: 'is' | 'some' | 'every' | 'none' ) { + let selector: string; + let operand: Expression | undefined; + if (isReferenceExpr(fieldAccess)) { - if (this.isRelationFieldAccess(fieldAccess)) { - this.writer.write(fieldAccess.target.ref?.name! + ': '); - this.writer.block(() => { - this.writer.write('is: '); - writeCondition(); - }); - } else { - this.writer.write(fieldAccess.target.ref?.name! + ': '); - writeCondition(); - } + selector = fieldAccess.target.ref?.name!; } else if (isMemberAccessExpr(fieldAccess)) { - this.writeFieldCondition(fieldAccess.operand, () => { - this.writer.block(() => { - this.writer.write(fieldAccess.member.ref?.name! + ': '); - writeCondition(); - }); - }); + selector = fieldAccess.member.ref?.name!; + operand = fieldAccess.operand; } else { throw new GeneratorError( `Unsupported expression type: ${fieldAccess.$type}` ); } + + if (operand) { + // member access expression + this.writeFieldCondition( + operand, + () => { + this.writer.block(() => { + this.writer.write(selector + ': '); + if (this.isModelTyped(fieldAccess)) { + // expression is resolved to a model, generate relation query + this.writer.block(() => { + this.writer.write(`${relationOp}: `); + writeCondition(); + }); + } else { + // generate plain query + writeCondition(); + } + }); + }, + 'is' + ); + } else if (this.isModelTyped(fieldAccess)) { + // reference resolved to a model, generate relation query + this.writer.write(selector + ': '); + this.writer.block(() => { + this.writer.write(`${relationOp}: `); + writeCondition(); + }); + } else { + // generate a plain query + this.writer.write(selector + ': '); + writeCondition(); + } + } + + private isModelTyped(expr: Expression) { + return isDataModel((expr as TypedNode).$resolvedType?.decl); } private isRelationFieldAccess(expr: Expression): boolean { diff --git a/packages/schema/src/language-server/generated/ast.ts b/packages/schema/src/language-server/generated/ast.ts index 3629f1800..0ebbb400f 100644 --- a/packages/schema/src/language-server/generated/ast.ts +++ b/packages/schema/src/language-server/generated/ast.ts @@ -115,7 +115,7 @@ export function isAttributeParamType(item: unknown): item is AttributeParamType export interface BinaryExpr extends AstNode { readonly $container: Argument | ArrayExpr | AttributeArg | BinaryExpr | DataSourceField | Function | MemberAccessExpr | UnaryExpr; left: Expression - operator: '!' | '!=' | '&&' | '<' | '<=' | '==' | '>' | '>=' | '?' | '||' + operator: '!' | '!=' | '&&' | '<' | '<=' | '==' | '>' | '>=' | '?' | '^' | '||' right: Expression } diff --git a/packages/schema/src/language-server/generated/grammar.ts b/packages/schema/src/language-server/generated/grammar.ts index 51c47a6b4..e0a670a29 100644 --- a/packages/schema/src/language-server/generated/grammar.ts +++ b/packages/schema/src/language-server/generated/grammar.ts @@ -690,6 +690,10 @@ export const ZModelGrammar = (): Grammar => loadedZModelGrammar ||(loadedZModelG { "$type": "Keyword", "value": "!" + }, + { + "$type": "Keyword", + "value": "^" } ] } diff --git a/packages/schema/src/language-server/zmodel-linker.ts b/packages/schema/src/language-server/zmodel-linker.ts index 9132841d4..d2c32ab45 100644 --- a/packages/schema/src/language-server/zmodel-linker.ts +++ b/packages/schema/src/language-server/zmodel-linker.ts @@ -199,6 +199,8 @@ export class ZModelLinker extends DefaultLinker { break; case '?': + case '!': + case '^': this.resolveCollectionPredicate(node, document, extraScopes); break; diff --git a/packages/schema/src/language-server/zmodel.langium b/packages/schema/src/language-server/zmodel.langium index 86f37a345..053e798b1 100644 --- a/packages/schema/src/language-server/zmodel.langium +++ b/packages/schema/src/language-server/zmodel.langium @@ -60,7 +60,7 @@ MemberAccessExpr infers Expression: CollectionPredicateExpr infers Expression: MemberAccessExpr ( {infer BinaryExpr.left=current} - operator=('?'|'!') + operator=('?'|'!'|'^') '[' right=Expression ']' )*; diff --git a/packages/schema/tests/generator/expression-writer.test.ts b/packages/schema/tests/generator/expression-writer.test.ts index 4bcfe031e..c268346df 100644 --- a/packages/schema/tests/generator/expression-writer.test.ts +++ b/packages/schema/tests/generator/expression-writer.test.ts @@ -10,7 +10,8 @@ import expressionWriter from '../../src/generator/server/expression-writer'; async function check( schema: string, - getExpr: (model: DataModel) => Expression + getExpr: (model: DataModel) => Expression, + expected: string ) { const model = await loadModel(schema); const expr = getExpr( @@ -25,7 +26,6 @@ async function check( const sf = project.createSourceFile(sourcePath, undefined, { overwrite: true, }); - console.log(`Generated source: ${sourcePath}`); sf.addVariableStatement({ declarationKind: VariableDeclarationKind.Const, @@ -50,12 +50,19 @@ async function check( for (const d of project.getPreEmitDiagnostics()) { console.warn(`${d.getLineNumber()}: ${d.getMessageText()}`); } + console.log(`Generated source: ${sourcePath}`); throw new Error('Compilation errors occurred'); } const outExpr = sf.getVariableDeclaration('expr'); - console.log('Generated expr:\n', outExpr?.getText()); - return outExpr?.getInitializer(); + // console.log('Generated expr:\n', outExpr?.getText()); + + if (expected) { + const generatedExpr = outExpr!.getInitializer()!.getText(); + expect(generatedExpr.replace(/\s+/g, '')).toBe( + expected.replace(/\s+/g, '') + ); + } } describe('Expression Writer Tests', () => { @@ -66,7 +73,8 @@ describe('Expression Writer Tests', () => { @@allow('all', true) } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ zenstack_guard: true }` ); await check( @@ -75,7 +83,8 @@ describe('Expression Writer Tests', () => { @@allow('all', false) } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ zenstack_guard: false }` ); }); @@ -87,7 +96,8 @@ describe('Expression Writer Tests', () => { @@allow('all', flag) } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ flag: true }` ); await check( @@ -97,7 +107,8 @@ describe('Expression Writer Tests', () => { @@allow('all', !flag) } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ NOT: { flag: true } }` ); }); @@ -105,11 +116,16 @@ describe('Expression Writer Tests', () => { await check( ` model Test { - count Int - @@allow('all', count > 0) + x Int + @@allow('all', x > 0) } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ + x: { + gt: 0 + } + }` ); await check( @@ -119,7 +135,12 @@ describe('Expression Writer Tests', () => { @@allow('all', label == 'thing') } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ + label: { + equals: 'thing' + } + }` ); }); @@ -127,41 +148,133 @@ describe('Expression Writer Tests', () => { await check( ` model Test { - count Int - @@allow('all', count > 0 && count > 1) + x Int + @@allow('all', x > 0 && x > 1) } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ + AND: + [ + { + x : { + gt: 0 + } + } + , + { + x : { + gt: 1 + } + } + ] + }` ); await check( ` model Test { - count Int - @@allow('all', count > 0 || count > 1) + x Int + @@allow('all', x > 0 || x > 1) } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ + OR: + [ + { + x : { + gt: 0 + } + } + , + { + x : { + gt: 1 + } + } + ] + }` ); await check( ` model Test { - count Int - @@allow('all', count > 0 && count > 1 || count > 2) + x Int + @@allow('all', x > 0 && x > 1 || x > 2) } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ + OR: + [ + { + AND: + [ + { + x : { + gt: 0 + } + } + , + { + x : { + gt: 1 + } + } + ] + } + , + { + x : { + gt: 2 + } + } + ] + }` ); await check( ` model Test { - count Int - @@allow('all', !(count > 0 && count > 1 || !count > 2)) + x Int + @@allow('all', !(x > 0 && x > 1 || !x > 2)) } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ + NOT: + { + OR: + [ + { + AND: + [ + { + x : { + gt: 0 + } + } + , + { + x : { + gt: 1 + } + } + ] + } + , + { + NOT: + { + x : { + gt: 2 + } + } + } + ] + } + }` ); }); @@ -169,29 +282,183 @@ describe('Expression Writer Tests', () => { await check( ` model Foo { - count Int + x Int + } + + model Test { + foo Foo + @@deny(foo.x <= 0) + } + `, + (model) => model.attributes[0].args[0].value, + `{ + foo: { + is: { + x : { + le: 0 + } + } + } + }` + ); + + await check( + ` + model Foo { + x Int + } + + model Test { + foo Foo + @@deny(!(foo.x > 0)) + } + `, + (model) => model.attributes[0].args[0].value, + `{ + NOT: + { + foo: { + is: { + x : { + gt: 0 + } + } + } + } + }` + ); + + await check( + ` + model Foo { + bar Bar + } + + model Bar { + x Int } model Test { foo Foo - @@deny(foo.count <= 0) + @@deny(foo.bar.x <= 0) } `, - (model) => model.attributes[0].args[0].value + (model) => model.attributes[0].args[0].value, + `{ + foo: { + is: { + bar: { + is: { + x : { + le: 0 + } + } + } + } + } + }` ); + }); + it('to-many relation query', async () => { await check( ` model Foo { - count Int + x Int + } + + model Test { + foos Foo[] + @@deny(foos?[x <= 0]) + } + `, + (model) => model.attributes[0].args[0].value, + `{ + foos: { + some: { + x: { + le: 0 + } + } + } + }` + ); + + await check( + ` + model Foo { + x Int + } + + model Test { + foos Foo[] + @@deny(foos![x <= 0]) + } + `, + (model) => model.attributes[0].args[0].value, + `{ + foos: { + every: { + x: { + le: 0 + } + } + } + }` + ); + + await check( + ` + model Foo { + x Int + } + + model Test { + foos Foo[] + @@deny(foos^[x <= 0]) + } + `, + (model) => model.attributes[0].args[0].value, + `{ + foos: { + none: { + x: { + le: 0 + } + } + } + }` + ); + + await check( + ` + model Foo { + bars Bar[] + } + + model Bar { + x Int } model Test { foo Foo - @@deny(!(foo.count > 0)) + @@deny(foo.bars?[x <= 0]) } `, - (model) => model.attributes[0].args[0].value + (model) => model.attributes[0].args[0].value, + `{ + foo: { + is: { + bars: { + some: { + x: { + le: 0 + } + } + } + } + } + }` ); }); @@ -202,7 +469,8 @@ describe('Expression Writer Tests', () => { @@deny(auth() == null) } `, - (model) => model.attributes[0].args[0].value + (model) => model.attributes[0].args[0].value, + `{ zenstack_guard: user == null }` ); await check( @@ -211,7 +479,8 @@ describe('Expression Writer Tests', () => { @@allow('all', auth() != null) } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ zenstack_guard: user != null }` ); }); @@ -228,7 +497,16 @@ describe('Expression Writer Tests', () => { @@allow('all', auth() == owner) } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ + owner: { + is: { + id: { + equals: user.id + } + } + } + }` ); await check( @@ -243,7 +521,18 @@ describe('Expression Writer Tests', () => { @@deny(auth() != owner) } `, - (model) => model.attributes[0].args[0].value + (model) => model.attributes[0].args[0].value, + `{ + owner: { + is: { + id: { + not: { + equals: user.id + } + } + } + } + }` ); await check( @@ -258,7 +547,16 @@ describe('Expression Writer Tests', () => { @@allow('all', auth().id == owner.id) } `, - (model) => model.attributes[0].args[1].value + (model) => model.attributes[0].args[1].value, + `{ + owner: { + is: { + id: { + equals: user.id + } + } + } + }` ); }); }); From 3d0a85fec558fbd68f22463dd70c168c9e4fa6ed Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Sat, 8 Oct 2022 22:39:45 +0800 Subject: [PATCH 07/15] WIP --- .../schema/src/generator/next-auth/index.ts | 34 ++-- .../src/generator/server/data-generator.ts | 145 ++++++++++++++--- .../src/generator/server/expression-writer.ts | 149 +++++------------- .../generator/server/js-expression-builder.ts | 72 +++++++++ .../schema/src/generator/service/index.ts | 2 +- .../tests/generator/expression-writer.test.ts | 36 ++--- samples/todo/schema.zmodel | 3 +- 7 files changed, 276 insertions(+), 165 deletions(-) create mode 100644 packages/schema/src/generator/server/js-expression-builder.ts diff --git a/packages/schema/src/generator/next-auth/index.ts b/packages/schema/src/generator/next-auth/index.ts index f8188709f..785c7a678 100644 --- a/packages/schema/src/generator/next-auth/index.ts +++ b/packages/schema/src/generator/next-auth/index.ts @@ -35,25 +35,25 @@ export default class NextAuthGenerator implements Generator { import { Prisma } from '@zenstack/.prisma'; export function NextAuthAdapter(service: ZenStackService): Adapter { - const p = service.prisma; + const db = service.db; return { - createUser: (data) => p.user.create({ data: data as Prisma.UserCreateInput }), - getUser: (id) => p.user.findUnique({ where: { id } }), - getUserByEmail: (email) => p.user.findUnique({ where: { email } }), + createUser: (data) => db.user.create({ data: data as Prisma.UserCreateInput }), + getUser: (id) => db.user.findUnique({ where: { id } }), + getUserByEmail: (email) => db.user.findUnique({ where: { email } }), async getUserByAccount(provider_providerAccountId) { - const account = await p.account.findUnique({ + const account = await db.account.findUnique({ where: { provider_providerAccountId }, select: { user: true }, }); return account?.user ?? null; }, - updateUser: (data) => p.user.update({ where: { id: data.id }, data: data as Prisma.UserUpdateInput }), - deleteUser: (id) => p.user.delete({ where: { id } }), - linkAccount: (data) => p.account.create({ data }) as any, + updateUser: (data) => db.user.update({ where: { id: data.id }, data: data as Prisma.UserUpdateInput }), + deleteUser: (id) => db.user.delete({ where: { id } }), + linkAccount: (data) => db.account.create({ data }) as any, unlinkAccount: (provider_providerAccountId) => - p.account.delete({ where: { provider_providerAccountId } }) as any, + db.account.delete({ where: { provider_providerAccountId } }) as any, async getSessionAndUser(sessionToken) { - const userAndSession = await p.session.findUnique({ + const userAndSession = await db.session.findUnique({ where: { sessionToken }, include: { user: true }, }); @@ -61,18 +61,18 @@ export default class NextAuthGenerator implements Generator { const { user, ...session } = userAndSession; return { user, session }; }, - createSession: (data) => p.session.create({ data }), + createSession: (data) => db.session.create({ data }), updateSession: (data) => - p.session.update({ + db.session.update({ data, where: { sessionToken: data.sessionToken }, }), deleteSession: (sessionToken) => - p.session.delete({ where: { sessionToken } }), - createVerificationToken: (data) => p.verificationToken.create({ data }), + db.session.delete({ where: { sessionToken } }), + createVerificationToken: (data) => db.verificationToken.create({ data }), async useVerificationToken(identifier_token) { try { - return await p.verificationToken.delete({ + return await db.verificationToken.delete({ where: { identifier_token }, }); } catch (error) { @@ -119,7 +119,7 @@ export default class NextAuthGenerator implements Generator { credentials: Record<'email' | 'password', string> | undefined ) => { try { - let maybeUser = await service.prisma.user.findFirst({ + let maybeUser = await service.db.user.findFirst({ where: { email: credentials!.email, }, @@ -136,7 +136,7 @@ export default class NextAuthGenerator implements Generator { throw new Error('Invalid Credentials'); } - maybeUser = await service.prisma.user.create({ + maybeUser = await service.db.user.create({ data: { email: credentials!.email, password: await hashPassword(credentials!.password), diff --git a/packages/schema/src/generator/server/data-generator.ts b/packages/schema/src/generator/server/data-generator.ts index 80b8100fb..8e4fd441f 100644 --- a/packages/schema/src/generator/server/data-generator.ts +++ b/packages/schema/src/generator/server/data-generator.ts @@ -16,6 +16,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { generate(project: Project, context: Context): void { const models = extractDataModelsWithAllowRules(context.schema); this.generateIndex(models, project, context); + this.generateUtils(project, context); models.forEach((model) => this.generateForModel(model, project, context) ); @@ -31,7 +32,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { import { RequestionHandlerOptions } from '..'; ${models.map((model) => this.writeModelImport(model)).join('\n')} - export default async private ( + export default async function ( req: NextApiRequest, res: NextApiResponse, path: string[], @@ -55,6 +56,35 @@ export default class DataServerGenerator implements ServerCodeGenerator { sf.formatText(); } + private generateUtils(project: Project, context: Context) { + const content = ` + import type { NextApiRequest, NextApiResponse } from 'next'; + import { RequestionHandlerOptions } from '..'; + + export async function getUser( + req: NextApiRequest, + res: NextApiResponse, + options: RequestionHandlerOptions + ): Promise<{id: string}> { + return await options.getServerUser(req, res); + } + + export function unauthorized(res: NextApiResponse) { + res.status(403).json({ message: 'Unauthorized' }); + } + + export function notFound(res: NextApiResponse) { + res.status(404).json({ message: 'Entity not found' }); + } + `; + const sf = project.createSourceFile( + path.join(context.outDir, 'server/data/_utils.ts'), + content, + { overwrite: true } + ); + sf.formatText(); + } + private writeModelImport(model: DataModel) { return `import ${camelCase(model.name)}Handler from './${paramCase( model.name @@ -75,10 +105,12 @@ export default class DataServerGenerator implements ServerCodeGenerator { ) { const content = ` import type { NextApiRequest, NextApiResponse } from 'next'; + import type { Prisma } from '@zenstack/.prisma'; import { RequestionHandlerOptions } from '..'; import service from '@zenstack/service'; + import { getUser, notFound } from './_utils'; - export default async private ( + export default async function ( req: NextApiRequest, res: NextApiResponse, path: string[], @@ -116,6 +148,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { ); this.generateFind(sf, model); + this.generateGet(sf, model); sf.formatText(); } @@ -144,7 +177,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { func.addStatements([ `const user = await getUser(req, res, options);`, - `const condition = req.query.q? (JSON.parse(req.query.q as string) as ${model.name}FindArgsInput): null;`, + `const condition: Prisma.${model.name}FindManyArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, ]); func.addVariableStatement({ @@ -152,39 +185,113 @@ export default class DataServerGenerator implements ServerCodeGenerator { declarations: [ { name: 'args', - type: 'TodoListFindArgsInput', - initializer: (writer) => this.writeFindArgs(writer, model), + type: `Prisma.${model.name}FindManyArgs`, + initializer: (writer) => { + writer.block(() => { + writer.writeLine('...condition,'); + writer.write('where:'); + writer.block(() => { + writer.write('AND: ['); + writer.write('{ ...condition.where },'); + this.writeFindArgs(writer, model); + writer.write(']'); + }); + }); + }, }, ], }); func.addStatements([ - `res.status(200).send(await service.prisma.todoList.findMany(args));`, + `res.status(200).send(await service.db.${camelCase( + model.name + )}.findMany(args));`, ]); } - private writeFindArgs(writer: CodeBlockWriter, model: DataModel) { - writer.block(() => { - writer.writeLine('where:'); - writer.block(() => { - writer.indent(() => { - writer.writeLine('AND: ['); + private generateGet(sourceFile: SourceFile, model: DataModel) { + const func = sourceFile + .addFunction({ + name: 'get', + isAsync: true, + parameters: [ + { + name: 'req', + type: 'NextApiRequest', + }, + { + name: 'res', + type: 'NextApiResponse', + }, + { + name: 'id', + type: 'string', + }, + { + name: 'options', + type: 'RequestionHandlerOptions', + }, + ], + }) + .addBody(); + + func.addStatements([ + `const user = await getUser(req, res, options);`, + `const condition: Prisma.${model.name}FindManyArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, + ]); - this.writeDenyRules(writer, model); - this.writeAllowRules(writer, model); + func.addVariableStatement({ + declarationKind: VariableDeclarationKind.Const, + declarations: [ + { + name: 'args', + type: `Prisma.${model.name}FindManyArgs`, + initializer: (writer) => { + writer.block(() => { + writer.writeLine('...condition,'); + writer.write('where:'); + writer.block(() => { + writer.write('AND: ['); + writer.write('{ id },'); + this.writeFindArgs(writer, model); + writer.write(']'); + }); + }); + }, + }, + ], + }); + + func.addStatements([ + ` + const r = await service.db.${camelCase(model.name)}.findMany(args); + if (r.length == 0) { + notFound(res); + } else { + res.status(200).send(r[0]); + } + `, + ]); + } - writer.writeLine(']'); - }); - }); + private writeFindArgs(writer: CodeBlockWriter, model: DataModel) { + writer.block(() => { + writer.writeLine('AND: ['); + this.writeDenyRules(writer, model); + this.writeAllowRules(writer, model); + writer.writeLine(']'); }); } private writeDenyRules(writer: CodeBlockWriter, model: DataModel) { const attrs = model.attributes.filter( - (attr) => attr.args.length > 0 && attr.decl.ref?.name === 'deny' + (attr) => + attr.args.length > 0 && + attr.decl.ref?.name === 'deny' && + attr.args.length > 1 ); attrs.forEach((attr) => - this.writeDenyRule(writer, model, attr.args[0].value) + this.writeDenyRule(writer, model, attr.args[1].value) ); } diff --git a/packages/schema/src/generator/server/expression-writer.ts b/packages/schema/src/generator/server/expression-writer.ts index aec71a67b..5b24d114d 100644 --- a/packages/schema/src/generator/server/expression-writer.ts +++ b/packages/schema/src/generator/server/expression-writer.ts @@ -1,66 +1,51 @@ import { - ArrayExpr, BinaryExpr, Expression, - InvocationExpr, isDataModel, isDataModelField, isMemberAccessExpr, isReferenceExpr, LiteralExpr, MemberAccessExpr, - NullExpr, ReferenceExpr, ThisExpr, UnaryExpr, } from '../../language-server/generated/ast'; import { CodeBlockWriter } from 'ts-morph'; import { GeneratorError } from '../types'; -import { TypedNode } from 'language-server/types'; +import { TypedNode } from '../../language-server/types'; +import JsExpressionBuilder from './js-expression-builder'; const AUX_GUARD_FIELD = 'zenstack_guard'; -type Context = { - nested: boolean; -}; - type ComparisonOperator = '==' | '!=' | '>' | '>=' | '<' | '<='; export default class ExpressionWriter { + private readonly jsExpr = new JsExpressionBuilder(); + constructor(private readonly writer: CodeBlockWriter) {} - write(expr: Expression, context: Context = { nested: false }) { + write(expr: Expression) { const _write = () => { switch (expr.$type) { case LiteralExpr: - this.writeLiteral(expr as LiteralExpr, context); + this.writeLiteral(expr as LiteralExpr); break; case UnaryExpr: - this.writeUnary(expr as UnaryExpr, context); + this.writeUnary(expr as UnaryExpr); break; case BinaryExpr: - this.writeBinary(expr as BinaryExpr, context); + this.writeBinary(expr as BinaryExpr); break; case ReferenceExpr: - this.writeReference(expr as ReferenceExpr, context); - break; - - case InvocationExpr: - this.writeInvocation(expr as InvocationExpr, context); + this.writeReference(expr as ReferenceExpr); break; case MemberAccessExpr: - this.writeMemberAccess(expr as MemberAccessExpr, context); - break; - - case ArrayExpr: - throw new Error('Not implemented'); - - case NullExpr: - this.writeNull(context); + this.writeMemberAccess(expr as MemberAccessExpr); break; case ThisExpr: @@ -71,43 +56,25 @@ export default class ExpressionWriter { } }; - if (context.nested) { - _write(); - } else { - this.writer.block(_write); - } + this.writer.block(_write); } - private writeReference(expr: ReferenceExpr, context: Context) { + private writeReference(expr: ReferenceExpr) { if (!isDataModelField(expr.target.ref)) { throw new GeneratorError('must be a field in current model'); } this.writer.write(`${expr.target.ref.name}: true`); } - private writeMemberAccess(expr: MemberAccessExpr, context: Context) { - this.write(expr.operand, context); + private writeMemberAccess(expr: MemberAccessExpr) { + this.write(expr.operand); this.writer.write('.' + expr.member.ref?.name); } - private writeNull(context: Context) { - this.writer.write('null'); - } - - private writeInvocation(expr: InvocationExpr, context: Context) { - if (expr.function.ref?.name !== 'auth') { - throw new GeneratorError( - `Function invocation is not supported: ${expr.function.ref?.name}` - ); - } - - this.writer.write('user'); - } - - private writeExprList(exprs: Expression[], context: Context) { + private writeExprList(exprs: Expression[]) { this.writer.writeLine('['); for (let i = 0; i < exprs.length; i++) { - this.write(exprs[i], context); + this.write(exprs[i]); if (i !== exprs.length - 1) { this.writer.writeLine(','); } @@ -115,11 +82,11 @@ export default class ExpressionWriter { this.writer.writeLine(']'); } - private writeBinary(expr: BinaryExpr, context: Context) { + private writeBinary(expr: BinaryExpr) { switch (expr.operator) { case '&&': case '||': - this.writeLogical(expr, expr.operator, context); + this.writeLogical(expr, expr.operator); break; case '==': @@ -128,26 +95,22 @@ export default class ExpressionWriter { case '>=': case '<': case '<=': - this.writeComparison(expr, expr.operator, context); + this.writeComparison(expr, expr.operator); break; case '?': case '!': case '^': - this.writeCollectionPredicate(expr, expr.operator, context); + this.writeCollectionPredicate(expr, expr.operator); break; } } - private writeCollectionPredicate( - expr: BinaryExpr, - operator: string, - context: Context - ) { + private writeCollectionPredicate(expr: BinaryExpr, operator: string) { this.writeFieldCondition( expr.left, () => { - this.write(expr.right, context); + this.write(expr.right); }, operator === '?' ? 'some' : operator === '!' ? 'every' : 'none' ); @@ -166,17 +129,11 @@ export default class ExpressionWriter { write(); } - private quote(write: () => void) { - this.writer.write('('); - write(); - this.writer.write(')'); + private plain(expr: Expression) { + this.writer.write(this.jsExpr.build(expr)); } - private writeComparison( - expr: BinaryExpr, - operator: ComparisonOperator, - context: Context - ) { + private writeComparison(expr: BinaryExpr, operator: ComparisonOperator) { const leftIsFieldAccess = this.isFieldRef(expr.left) || this.isRelationFieldAccess(expr.left); const rightIsFieldAccess = @@ -191,12 +148,12 @@ export default class ExpressionWriter { if (!leftIsFieldAccess && !rightIsFieldAccess) { // compile down to a plain expression - const newContext = { ...context, nested: true }; this.guard(() => { - this.write(expr.left, newContext); + this.plain(expr.left); this.writer.write(' ' + operator + ' '); - this.write(expr.right, newContext); + this.plain(expr.right); }); + return; } @@ -222,16 +179,13 @@ export default class ExpressionWriter { this.writer.write('id: '); this.writer.block(() => { this.writeOperator(operator, () => { - this.write(operand, { - ...context, - nested: true, - }); + this.plain(operand); this.writer.write('.id'); }); }); } else { this.writeOperator(operator, () => { - this.write(operand, { ...context, nested: true }); + this.plain(operand); }); } }); @@ -364,48 +318,25 @@ export default class ExpressionWriter { } } - private writeLogical( - expr: BinaryExpr, - operator: '&&' | '||', - context: Context - ) { - if (context.nested) { - this.quote(() => this.write(expr.left, context)); - this.writer.write(operator); - this.quote(() => this.write(expr.right, context)); - } else { - this.writer.writeLine(`${operator === '&&' ? 'AND' : 'OR'}: `); - this.writeExprList([expr.left, expr.right], context); - } + private writeLogical(expr: BinaryExpr, operator: '&&' | '||') { + this.writer.writeLine(`${operator === '&&' ? 'AND' : 'OR'}: `); + this.writeExprList([expr.left, expr.right]); } - private writeUnary(expr: UnaryExpr, context: Context) { + private writeUnary(expr: UnaryExpr) { if (expr.operator !== '!') { throw new GeneratorError( `Unary operator "${expr.operator}" is not supported` ); } - if (context.nested) { - this.writer.write(expr.operator); - this.quote(() => this.write(expr.operand, context)); - } else { - this.writer.writeLine('NOT: '); - this.write(expr.operand, context); - } + this.writer.writeLine('NOT: '); + this.write(expr.operand); } - private writeLiteral(expr: LiteralExpr, context: Context) { - if (context.nested) { - if (typeof expr.value === 'string') { - this.writer.write(`'${expr.value.toString()}'`); - } else { - this.writer.write(expr.value.toString()); - } - } else { - this.guard(() => { - this.writer.write(expr.value.toString()); - }); - } + private writeLiteral(expr: LiteralExpr) { + this.guard(() => { + this.plain(expr); + }); } } diff --git a/packages/schema/src/generator/server/js-expression-builder.ts b/packages/schema/src/generator/server/js-expression-builder.ts new file mode 100644 index 000000000..a4445faac --- /dev/null +++ b/packages/schema/src/generator/server/js-expression-builder.ts @@ -0,0 +1,72 @@ +import { GeneratorError } from '../types'; +import { + ArrayExpr, + Expression, + InvocationExpr, + LiteralExpr, + MemberAccessExpr, + NullExpr, + ReferenceExpr, +} from '../../language-server/generated/ast'; + +export default class JsExpressionBuilder { + build(expr: Expression): string { + switch (expr.$type) { + case LiteralExpr: + return this.literal(expr as LiteralExpr); + + case ArrayExpr: + return this.array(expr as ArrayExpr); + + case NullExpr: + return this.null(); + + case ReferenceExpr: + return this.reference(expr as ReferenceExpr); + + case InvocationExpr: + return this.invocation(expr as InvocationExpr); + + case MemberAccessExpr: + return this.memberAccess(expr as MemberAccessExpr); + + default: + throw new GeneratorError( + `Unsupported expression type: ${expr.$type}` + ); + } + } + + private memberAccess(expr: MemberAccessExpr) { + return `${this.build(expr.operand)}.${expr.member.ref!.name}`; + } + + private invocation(expr: InvocationExpr) { + if (expr.function.ref?.name !== 'auth') { + throw new GeneratorError( + `Function invocation is not supported: ${expr.function.ref?.name}` + ); + } + return 'user'; + } + + private reference(expr: ReferenceExpr) { + return expr.target.ref!.name; + } + + private null() { + return 'null'; + } + + private array(expr: ArrayExpr) { + return `[${expr.items.map((item) => this.build(item)).join(', ')}]`; + } + + private literal(expr: LiteralExpr) { + if (typeof expr.value === 'string') { + return `'${expr.value}'`; + } else { + return expr.value.toString(); + } + } +} diff --git a/packages/schema/src/generator/service/index.ts b/packages/schema/src/generator/service/index.ts index ce671d75c..b24d99b3d 100644 --- a/packages/schema/src/generator/service/index.ts +++ b/packages/schema/src/generator/service/index.ts @@ -28,7 +28,7 @@ export default class ServiceGenerator implements Generator { }); cls.addGetAccessor({ - name: 'prisma', + name: 'db', }) .addBody() .setBodyText('return this._prisma;'); diff --git a/packages/schema/tests/generator/expression-writer.test.ts b/packages/schema/tests/generator/expression-writer.test.ts index c268346df..d9a85b710 100644 --- a/packages/schema/tests/generator/expression-writer.test.ts +++ b/packages/schema/tests/generator/expression-writer.test.ts @@ -287,10 +287,10 @@ describe('Expression Writer Tests', () => { model Test { foo Foo - @@deny(foo.x <= 0) + @@deny('all', foo.x <= 0) } `, - (model) => model.attributes[0].args[0].value, + (model) => model.attributes[0].args[1].value, `{ foo: { is: { @@ -310,10 +310,10 @@ describe('Expression Writer Tests', () => { model Test { foo Foo - @@deny(!(foo.x > 0)) + @@deny('all', !(foo.x > 0)) } `, - (model) => model.attributes[0].args[0].value, + (model) => model.attributes[0].args[1].value, `{ NOT: { @@ -340,10 +340,10 @@ describe('Expression Writer Tests', () => { model Test { foo Foo - @@deny(foo.bar.x <= 0) + @@deny('all', foo.bar.x <= 0) } `, - (model) => model.attributes[0].args[0].value, + (model) => model.attributes[0].args[1].value, `{ foo: { is: { @@ -369,10 +369,10 @@ describe('Expression Writer Tests', () => { model Test { foos Foo[] - @@deny(foos?[x <= 0]) + @@deny('all', foos?[x <= 0]) } `, - (model) => model.attributes[0].args[0].value, + (model) => model.attributes[0].args[1].value, `{ foos: { some: { @@ -392,10 +392,10 @@ describe('Expression Writer Tests', () => { model Test { foos Foo[] - @@deny(foos![x <= 0]) + @@deny('all', foos![x <= 0]) } `, - (model) => model.attributes[0].args[0].value, + (model) => model.attributes[0].args[1].value, `{ foos: { every: { @@ -415,10 +415,10 @@ describe('Expression Writer Tests', () => { model Test { foos Foo[] - @@deny(foos^[x <= 0]) + @@deny('all', foos^[x <= 0]) } `, - (model) => model.attributes[0].args[0].value, + (model) => model.attributes[0].args[1].value, `{ foos: { none: { @@ -442,10 +442,10 @@ describe('Expression Writer Tests', () => { model Test { foo Foo - @@deny(foo.bars?[x <= 0]) + @@deny('all', foo.bars?[x <= 0]) } `, - (model) => model.attributes[0].args[0].value, + (model) => model.attributes[0].args[1].value, `{ foo: { is: { @@ -466,10 +466,10 @@ describe('Expression Writer Tests', () => { await check( ` model Test { - @@deny(auth() == null) + @@deny('all', auth() == null) } `, - (model) => model.attributes[0].args[0].value, + (model) => model.attributes[0].args[1].value, `{ zenstack_guard: user == null }` ); @@ -518,10 +518,10 @@ describe('Expression Writer Tests', () => { model Test { id String @id owner User - @@deny(auth() != owner) + @@deny('all', auth() != owner) } `, - (model) => model.attributes[0].args[0].value, + (model) => model.attributes[0].args[1].value, `{ owner: { is: { diff --git a/samples/todo/schema.zmodel b/samples/todo/schema.zmodel index 1992233b7..71bdf6da0 100644 --- a/samples/todo/schema.zmodel +++ b/samples/todo/schema.zmodel @@ -22,7 +22,8 @@ model Space { todoLists TodoList[] // require login - @@deny('all', auth() == null) + @@deny('all', auth() == null) + // everyone can create a space @@allow('create', true) From acb38961ab67a1e38a60abc9f03a93444f3f580f Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Mon, 10 Oct 2022 09:26:52 +0800 Subject: [PATCH 08/15] Progress --- packages/schema/jest.config.ts | 153 +-------- packages/schema/package.json | 9 +- packages/schema/src/generator/prisma/index.ts | 2 +- .../schema/src/generator/react-hooks/index.ts | 6 +- .../server/{ => data}/data-generator.ts | 301 ++++++++++++++---- .../server/{ => data}/expression-writer.ts | 36 ++- .../plain-expression-builder.ts} | 8 +- .../{ => function}/function-generator.ts | 4 +- packages/schema/src/generator/server/index.ts | 8 +- packages/schema/src/generator/types.ts | 2 +- packages/schema/src/generator/utils.ts | 6 +- .../tests/generator/expression-writer.test.ts | 31 +- packages/schema/tsconfig.json | 6 +- pnpm-lock.yaml | 40 +++ samples/todo/.env | 9 +- samples/todo/components/AccessDenied.tsx | 5 +- samples/todo/package-lock.json | 11 + samples/todo/package.json | 3 +- samples/todo/pages/index.tsx | 51 +-- samples/todo/schema.zmodel | 15 +- 20 files changed, 417 insertions(+), 289 deletions(-) rename packages/schema/src/generator/server/{ => data}/data-generator.ts (53%) rename packages/schema/src/generator/server/{ => data}/expression-writer.ts (91%) rename packages/schema/src/generator/server/{js-expression-builder.ts => data/plain-expression-builder.ts} (89%) rename packages/schema/src/generator/server/{ => function}/function-generator.ts (90%) diff --git a/packages/schema/jest.config.ts b/packages/schema/jest.config.ts index 4b5c9766b..9f686b1cc 100644 --- a/packages/schema/jest.config.ts +++ b/packages/schema/jest.config.ts @@ -3,16 +3,10 @@ * https://jestjs.io/docs/configuration */ -export default { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "/private/var/folders/r7/j1xwztq57cl_s92mt6g410tc0000gn/T/jest_dx", +import tsconfig from './tsconfig.json'; +const moduleNameMapper = require('tsconfig-paths-jest')(tsconfig); +export default { // Automatically clear mock calls, instances, contexts and results before every test clearMocks: true, @@ -41,85 +35,6 @@ export default { // "clover" // ], - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: undefined, - - // A path to a custom dependency extractor - // dependencyExtractor: undefined, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // The default configuration for fake timers - // fakeTimers: { - // "enableGlobally": false - // }, - - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: undefined, - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, - - // A set of global variables that need to be available in all test environments - // globals: {}, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - // An array of file extensions your modules use - // moduleFileExtensions: [ - // "js", - // "mjs", - // "cjs", - // "jsx", - // "ts", - // "tsx", - // "json", - // "node" - // ], - - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - // moduleNameMapper: {}, - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - // preset: undefined, - - // Run tests from one or more projects - // projects: undefined, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state before every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: undefined, - - // Automatically restore mock state and implementation before every test - // restoreMocks: false, - // The root directory that Jest should scan for tests and modules within // rootDir: undefined, @@ -128,68 +43,8 @@ export default { // "" // ], - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], - - // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing - // testEnvironment: "jest-environment-node", - - // Options that will be passed to the testEnvironment - // testEnvironmentOptions: {}, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - // testMatch: [ - // "**/__tests__/**/*.[jt]s?(x)", - // "**/?(*.)+(spec|test).[tj]s?(x)" - // ], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "/node_modules/" - // ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: [], - - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, - - // This option allows use of a custom test runner - // testRunner: "jest-circus/runner", - // A map from regular expressions to paths to transformers transform: { '^.+\\.tsx?$': 'ts-jest' }, - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "/node_modules/", - // "\\.pnp\\.[^\\/]+$" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: undefined, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, + moduleNameMapper, }; diff --git a/packages/schema/package.json b/packages/schema/package.json index a1433e0e3..21adae7eb 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -49,12 +49,13 @@ "main": "./out/extension.js", "scripts": { "vscode:prepublish": "npm run build && npm run lint", - "build": "tsc -b tsconfig.json && cp src/language-server/stdlib.zmodel ./out/language-server/", - "ts:watch": "tsc -b tsconfig.json --watch", + "build": "tsc && tsc-alias && cp src/language-server/stdlib.zmodel ./out/language-server/", + "ts:watch": "tsc --watch", + "tsc-alias:watch": "tsc-alias --watch", "lint": "eslint src --ext ts", "langium:generate": "langium generate", "langium:watch": "langium generate --watch", - "watch": "concurrently \"npm:langium:watch\" \"npm:ts:watch\"", + "watch": "concurrently --kill-others \"npm:langium:watch\" \"npm:ts:watch\" \"npm:tsc-alias:watch\"", "test": "jest" }, "dependencies": { @@ -86,6 +87,8 @@ "tmp": "^0.2.1", "ts-jest": "^29.0.1", "ts-node": "^10.9.1", + "tsc-alias": "^1.7.0", + "tsconfig-paths-jest": "^0.0.1", "typescript": "^4.6.2" } } diff --git a/packages/schema/src/generator/prisma/index.ts b/packages/schema/src/generator/prisma/index.ts index d21837376..896faf18e 100644 --- a/packages/schema/src/generator/prisma/index.ts +++ b/packages/schema/src/generator/prisma/index.ts @@ -17,7 +17,7 @@ import { isLiteralExpr, isReferenceExpr, LiteralExpr, -} from '../../language-server/generated/ast'; +} from '@lang/generated/ast'; import { Context, Generator, GeneratorError } from '../types'; import { AttributeArg as PrismaAttributeArg, diff --git a/packages/schema/src/generator/react-hooks/index.ts b/packages/schema/src/generator/react-hooks/index.ts index d4a21d146..da786a9bf 100644 --- a/packages/schema/src/generator/react-hooks/index.ts +++ b/packages/schema/src/generator/react-hooks/index.ts @@ -2,7 +2,7 @@ import { Context, Generator } from '../types'; import { Project } from 'ts-morph'; import * as path from 'path'; import { camelCase, paramCase } from 'change-case'; -import { DataModel } from '../../language-server/generated/ast'; +import { DataModel } from '@lang/generated/ast'; import colors from 'colors'; import { extractDataModelsWithAllowRules } from '../utils'; @@ -180,7 +180,7 @@ export default class ReactHooksGenerator implements Generator { name: 'get', isAsync: true, typeParameters: [ - `T extends P.Subset`, + `T extends P.Subset`, ], parameters: [ { @@ -189,7 +189,7 @@ export default class ReactHooksGenerator implements Generator { }, { name: 'args?', - type: `P.SelectSubset>`, + type: `P.SelectSubset>`, }, ], }) diff --git a/packages/schema/src/generator/server/data-generator.ts b/packages/schema/src/generator/server/data/data-generator.ts similarity index 53% rename from packages/schema/src/generator/server/data-generator.ts rename to packages/schema/src/generator/server/data/data-generator.ts index 8e4fd441f..6edaf3bc3 100644 --- a/packages/schema/src/generator/server/data-generator.ts +++ b/packages/schema/src/generator/server/data/data-generator.ts @@ -1,16 +1,28 @@ -import { Context } from '../types'; +import { Context, GeneratorError } from '../../types'; import { CodeBlockWriter, + OptionalKind, + ParameterDeclarationStructure, Project, SourceFile, VariableDeclarationKind, } from 'ts-morph'; -import { DataModel, Expression } from '../../language-server/generated/ast'; +import { + DataModel, + Expression, + isInvocationExpr, + isLiteralExpr, +} from '@lang/generated/ast'; import * as path from 'path'; import { camelCase, paramCase } from 'change-case'; -import { extractDataModelsWithAllowRules } from '../utils'; -import { ServerCodeGenerator } from './server-code-generator'; +import { extractDataModelsWithAllowRules } from '../../utils'; +import { ServerCodeGenerator } from '../server-code-generator'; import ExpressionWriter from './expression-writer'; +import { streamAllContents } from 'langium'; +import colors from 'colors'; + +type ServerOperation = 'get' | 'create' | 'find' | 'update' | 'del'; +type PolicyAction = 'create' | 'read' | 'update' | 'delete'; export default class DataServerGenerator implements ServerCodeGenerator { generate(project: Project, context: Context): void { @@ -20,8 +32,12 @@ export default class DataServerGenerator implements ServerCodeGenerator { models.forEach((model) => this.generateForModel(model, project, context) ); + + console.log(colors.blue(' ✔️ Server-side CRUD generated')); } + //#region Index & Utils + private generateIndex( models: DataModel[], project: Project, @@ -65,7 +81,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { req: NextApiRequest, res: NextApiResponse, options: RequestionHandlerOptions - ): Promise<{id: string}> { + ) { return await options.getServerUser(req, res); } @@ -98,6 +114,10 @@ export default class DataServerGenerator implements ServerCodeGenerator { `; } + //#endregion + + //#region Per-Model + private generateForModel( model: DataModel, project: Project, @@ -149,35 +169,78 @@ export default class DataServerGenerator implements ServerCodeGenerator { this.generateFind(sf, model); this.generateGet(sf, model); + this.generateCreate(sf, model); + this.generateUpdate(sf, model); + this.generateDel(sf, model); sf.formatText(); + sf.saveSync(); } - private generateFind(sourceFile: SourceFile, model: DataModel) { + private generateServeFunction( + sourceFile: SourceFile, + model: DataModel, + operation: ServerOperation + ) { + const parameters: OptionalKind[] = []; + + parameters.push({ + name: 'req', + type: 'NextApiRequest', + }); + + parameters.push({ + name: 'res', + type: 'NextApiResponse', + }); + + if ( + operation === 'get' || + operation === 'update' || + operation === 'del' + ) { + // an extra "id" parameter + parameters.push({ + name: 'id', + type: 'string', + }); + } + + parameters.push({ + name: 'options', + type: 'RequestionHandlerOptions', + }); + const func = sourceFile .addFunction({ - name: 'find', + name: operation, isAsync: true, - parameters: [ - { - name: 'req', - type: 'NextApiRequest', - }, - { - name: 'res', - type: 'NextApiResponse', - }, - { - name: 'options', - type: 'RequestionHandlerOptions', - }, - ], + parameters, }) .addBody(); + if (this.modelUsesAuth(model)) { + func.addStatements([ + `const user = await getUser(req, res, options);`, + ]); + } + return func; + } + + private modelUsesAuth(model: DataModel) { + return !!streamAllContents(model).find( + (node) => + isInvocationExpr(node) && node.function.ref?.name === 'auth' + ); + } + + //#region Find & Get + + private generateFind(sourceFile: SourceFile, model: DataModel) { + const func = this.generateServeFunction(sourceFile, model, 'find'); + func.addStatements([ - `const user = await getUser(req, res, options);`, - `const condition: Prisma.${model.name}FindManyArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, + `const query: Prisma.${model.name}FindManyArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, ]); func.addVariableStatement({ @@ -188,12 +251,12 @@ export default class DataServerGenerator implements ServerCodeGenerator { type: `Prisma.${model.name}FindManyArgs`, initializer: (writer) => { writer.block(() => { - writer.writeLine('...condition,'); + writer.writeLine('...query,'); writer.write('where:'); writer.block(() => { writer.write('AND: ['); - writer.write('{ ...condition.where },'); - this.writeFindArgs(writer, model); + writer.write('{ ...query.where },'); + this.writeFindArgs(writer, model, 'read'); writer.write(']'); }); }); @@ -210,34 +273,10 @@ export default class DataServerGenerator implements ServerCodeGenerator { } private generateGet(sourceFile: SourceFile, model: DataModel) { - const func = sourceFile - .addFunction({ - name: 'get', - isAsync: true, - parameters: [ - { - name: 'req', - type: 'NextApiRequest', - }, - { - name: 'res', - type: 'NextApiResponse', - }, - { - name: 'id', - type: 'string', - }, - { - name: 'options', - type: 'RequestionHandlerOptions', - }, - ], - }) - .addBody(); + const func = this.generateServeFunction(sourceFile, model, 'get'); func.addStatements([ - `const user = await getUser(req, res, options);`, - `const condition: Prisma.${model.name}FindManyArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, + `const query: Prisma.${model.name}FindFirstArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, ]); func.addVariableStatement({ @@ -245,15 +284,15 @@ export default class DataServerGenerator implements ServerCodeGenerator { declarations: [ { name: 'args', - type: `Prisma.${model.name}FindManyArgs`, + type: `Prisma.${model.name}FindFirstArgs`, initializer: (writer) => { writer.block(() => { - writer.writeLine('...condition,'); + writer.writeLine('...query,'); writer.write('where:'); writer.block(() => { writer.write('AND: ['); writer.write('{ id },'); - this.writeFindArgs(writer, model); + this.writeFindArgs(writer, model, 'read'); writer.write(']'); }); }); @@ -264,31 +303,138 @@ export default class DataServerGenerator implements ServerCodeGenerator { func.addStatements([ ` - const r = await service.db.${camelCase(model.name)}.findMany(args); - if (r.length == 0) { + const r = await service.db.${camelCase(model.name)}.findFirst(args); + if (!r) { notFound(res); } else { - res.status(200).send(r[0]); + res.status(200).send(r); } `, ]); } - private writeFindArgs(writer: CodeBlockWriter, model: DataModel) { + private writeFindArgs( + writer: CodeBlockWriter, + model: DataModel, + action: PolicyAction + ) { writer.block(() => { writer.writeLine('AND: ['); - this.writeDenyRules(writer, model); - this.writeAllowRules(writer, model); + this.writeDenyRules(writer, model, action); + this.writeAllowRules(writer, model, action); writer.writeLine(']'); }); } - private writeDenyRules(writer: CodeBlockWriter, model: DataModel) { + //#endregion + + //#region Create + + private generateCreate(sourceFile: SourceFile, model: DataModel) { + const func = this.generateServeFunction(sourceFile, model, 'create'); + + func.addVariableStatement({ + declarationKind: VariableDeclarationKind.Const, + declarations: [ + { + name: 'args', + type: `Prisma.${model.name}CreateArgs`, + initializer: 'req.body', + }, + ], + }); + + // TODO: policy + + func.addStatements([ + ` + const r = await service.db.${camelCase(model.name)}.create(args); + res.status(200).send(r); + `, + ]); + } + + //#endregion + + //#region Update + + private generateUpdate(sourceFile: SourceFile, model: DataModel) { + const func = this.generateServeFunction(sourceFile, model, 'update'); + + func.addVariableStatement({ + declarationKind: VariableDeclarationKind.Const, + declarations: [ + { + name: 'body', + type: `Prisma.${model.name}UpdateArgs`, + initializer: 'req.body', + }, + ], + }); + + // TODO: policy + + func.addStatements([ + ` + const r = await service.db.${camelCase(model.name)}.update({ + ...body, + where: { id } + }); + res.status(200).send(r); + `, + ]); + } + + //#endregion + + //#region Delete + + private generateDel(sourceFile: SourceFile, model: DataModel) { + const func = this.generateServeFunction(sourceFile, model, 'del'); + + func.addStatements([ + `const args: Prisma.${model.name}DeleteArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, + ]); + + // TODO: policy + + func.addStatements([ + ` + const r = await service.db.${camelCase(model.name)}.delete({ + ...args, + where: { id } + }); + res.status(200).send(r); + `, + ]); + } + + //#endregion + + //#endregion + + //#region Policy + + private ruleSpecCovers(ruleSpec: Expression, action: string) { + if (!isLiteralExpr(ruleSpec) || typeof ruleSpec.value !== 'string') { + throw new GeneratorError(`Rule spec must be a string literal`); + } + + const specs = ruleSpec.value.split(',').map((s) => s.trim()); + return specs.includes('all') || specs.includes(action); + } + + private writeDenyRules( + writer: CodeBlockWriter, + model: DataModel, + action: PolicyAction + ) { const attrs = model.attributes.filter( (attr) => attr.args.length > 0 && attr.decl.ref?.name === 'deny' && - attr.args.length > 1 + attr.args.length > 1 && + this.ruleSpecCovers(attr.args[0].value, action) ); attrs.forEach((attr) => this.writeDenyRule(writer, model, attr.args[1].value) @@ -304,9 +450,34 @@ export default class DataServerGenerator implements ServerCodeGenerator { writer.writeLine('NOT: '); new ExpressionWriter(writer).write(rule); }); + writer.write(','); + } + + private writeAllowRules( + writer: CodeBlockWriter, + model: DataModel, + action: PolicyAction + ) { + const attrs = model.attributes.filter( + (attr) => + attr.args.length > 0 && + attr.decl.ref?.name === 'allow' && + attr.args.length > 1 && + this.ruleSpecCovers(attr.args[0].value, action) + ); + attrs.forEach((attr) => + this.writeAllowRule(writer, model, attr.args[1].value) + ); } - private writeAllowRules(writer: CodeBlockWriter, model: DataModel) { - // throw new Error('private not implemented.'); + private writeAllowRule( + writer: CodeBlockWriter, + model: DataModel, + rule: Expression + ) { + new ExpressionWriter(writer).write(rule); + writer.write(','); } + + //#endregion } diff --git a/packages/schema/src/generator/server/expression-writer.ts b/packages/schema/src/generator/server/data/expression-writer.ts similarity index 91% rename from packages/schema/src/generator/server/expression-writer.ts rename to packages/schema/src/generator/server/data/expression-writer.ts index 5b24d114d..44cb402b7 100644 --- a/packages/schema/src/generator/server/expression-writer.ts +++ b/packages/schema/src/generator/server/data/expression-writer.ts @@ -3,6 +3,7 @@ import { Expression, isDataModel, isDataModelField, + isEnumField, isMemberAccessExpr, isReferenceExpr, LiteralExpr, @@ -10,18 +11,18 @@ import { ReferenceExpr, ThisExpr, UnaryExpr, -} from '../../language-server/generated/ast'; +} from '@lang/generated/ast'; import { CodeBlockWriter } from 'ts-morph'; -import { GeneratorError } from '../types'; -import { TypedNode } from '../../language-server/types'; -import JsExpressionBuilder from './js-expression-builder'; +import { GeneratorError } from '../../types'; +import { TypedNode } from '@lang/types'; +import PlainExpressionBuilder from './plain-expression-builder'; const AUX_GUARD_FIELD = 'zenstack_guard'; type ComparisonOperator = '==' | '!=' | '>' | '>=' | '<' | '<='; export default class ExpressionWriter { - private readonly jsExpr = new JsExpressionBuilder(); + private readonly plainExprBuilder = new PlainExpressionBuilder(); constructor(private readonly writer: CodeBlockWriter) {} @@ -60,15 +61,23 @@ export default class ExpressionWriter { } private writeReference(expr: ReferenceExpr) { - if (!isDataModelField(expr.target.ref)) { - throw new GeneratorError('must be a field in current model'); + if (isEnumField(expr.target.ref)) { + throw new Error('Not implemented'); + } else { + this.writer.write(`${expr.target.ref!.name}: true`); } - this.writer.write(`${expr.target.ref.name}: true`); } private writeMemberAccess(expr: MemberAccessExpr) { - this.write(expr.operand); - this.writer.write('.' + expr.member.ref?.name); + this.writeFieldCondition( + expr.operand, + () => { + this.writer.block(() => { + this.writer.write(`${expr.member.ref?.name}: true`); + }); + }, + 'is' + ); } private writeExprList(exprs: Expression[]) { @@ -130,7 +139,7 @@ export default class ExpressionWriter { } private plain(expr: Expression) { - this.writer.write(this.jsExpr.build(expr)); + this.writer.write(this.plainExprBuilder.build(expr)); } private writeComparison(expr: BinaryExpr, operator: ComparisonOperator) { @@ -180,7 +189,7 @@ export default class ExpressionWriter { this.writer.block(() => { this.writeOperator(operator, () => { this.plain(operand); - this.writer.write('.id'); + this.writer.write('?.id'); }); }); } else { @@ -290,8 +299,7 @@ export default class ExpressionWriter { case '==': return 'equals'; case '!=': - // TODO - return 'not_equal'; + throw new Error('Operation != should have been compiled away'); case '>': return 'gt'; case '>=': diff --git a/packages/schema/src/generator/server/js-expression-builder.ts b/packages/schema/src/generator/server/data/plain-expression-builder.ts similarity index 89% rename from packages/schema/src/generator/server/js-expression-builder.ts rename to packages/schema/src/generator/server/data/plain-expression-builder.ts index a4445faac..1fe530adf 100644 --- a/packages/schema/src/generator/server/js-expression-builder.ts +++ b/packages/schema/src/generator/server/data/plain-expression-builder.ts @@ -1,4 +1,4 @@ -import { GeneratorError } from '../types'; +import { GeneratorError } from '../../types'; import { ArrayExpr, Expression, @@ -7,9 +7,9 @@ import { MemberAccessExpr, NullExpr, ReferenceExpr, -} from '../../language-server/generated/ast'; +} from '@lang/generated/ast'; -export default class JsExpressionBuilder { +export default class PlainExpressionBuilder { build(expr: Expression): string { switch (expr.$type) { case LiteralExpr: @@ -38,7 +38,7 @@ export default class JsExpressionBuilder { } private memberAccess(expr: MemberAccessExpr) { - return `${this.build(expr.operand)}.${expr.member.ref!.name}`; + return `${this.build(expr.operand)}?.${expr.member.ref!.name}`; } private invocation(expr: InvocationExpr) { diff --git a/packages/schema/src/generator/server/function-generator.ts b/packages/schema/src/generator/server/function/function-generator.ts similarity index 90% rename from packages/schema/src/generator/server/function-generator.ts rename to packages/schema/src/generator/server/function/function-generator.ts index 92681ccc8..5f29f02f0 100644 --- a/packages/schema/src/generator/server/function-generator.ts +++ b/packages/schema/src/generator/server/function/function-generator.ts @@ -1,7 +1,7 @@ -import { Context } from '../types'; +import { Context } from '../../types'; import { Project } from 'ts-morph'; import * as path from 'path'; -import { ServerCodeGenerator } from './server-code-generator'; +import { ServerCodeGenerator } from '../server-code-generator'; export default class FunctionServerGenerator implements ServerCodeGenerator { generate(project: Project, context: Context) { diff --git a/packages/schema/src/generator/server/index.ts b/packages/schema/src/generator/server/index.ts index 8ae354a53..5836d9d44 100644 --- a/packages/schema/src/generator/server/index.ts +++ b/packages/schema/src/generator/server/index.ts @@ -1,8 +1,8 @@ import { Project } from 'ts-morph'; import { Context, Generator } from '../types'; import * as path from 'path'; -import DataServerGenerator from './data-generator'; -import FunctionServerGenerator from './function-generator'; +import DataServerGenerator from './data/data-generator'; +import FunctionServerGenerator from './function/function-generator'; export default class ServerGenerator implements Generator { async generate(context: Context) { @@ -22,11 +22,13 @@ export default class ServerGenerator implements Generator { import dataHandler from './data'; import functionHandler from './function'; + export type AuthUser = { id: string } & Record; + export type RequestionHandlerOptions = { getServerUser: ( req: NextApiRequest, res: NextApiResponse - ) => Promise<{ id: string } | undefined>; + ) => Promise; }; export function RequestHandler(options: RequestionHandlerOptions) { diff --git a/packages/schema/src/generator/types.ts b/packages/schema/src/generator/types.ts index 0f63d3e35..2816cf2e9 100644 --- a/packages/schema/src/generator/types.ts +++ b/packages/schema/src/generator/types.ts @@ -1,4 +1,4 @@ -import { Model } from '../language-server/generated/ast'; +import { Model } from '@lang/generated/ast'; export interface Context { schema: Model; diff --git a/packages/schema/src/generator/utils.ts b/packages/schema/src/generator/utils.ts index 580f6dbfe..52c35139e 100644 --- a/packages/schema/src/generator/utils.ts +++ b/packages/schema/src/generator/utils.ts @@ -1,8 +1,4 @@ -import { - DataModel, - isDataModel, - Model, -} from '../language-server/generated/ast'; +import { DataModel, isDataModel, Model } from '@lang/generated/ast'; export function extractDataModelsWithAllowRules(model: Model) { return model.declarations.filter( diff --git a/packages/schema/tests/generator/expression-writer.test.ts b/packages/schema/tests/generator/expression-writer.test.ts index d9a85b710..42fa1dd5c 100644 --- a/packages/schema/tests/generator/expression-writer.test.ts +++ b/packages/schema/tests/generator/expression-writer.test.ts @@ -6,7 +6,7 @@ import { } from '../../src/language-server/generated/ast'; import { loadModel } from '../utils'; import * as tmp from 'tmp'; -import expressionWriter from '../../src/generator/server/expression-writer'; +import expressionWriter from '../../src/generator/server/data/expression-writer'; async function check( schema: string, @@ -328,6 +328,29 @@ describe('Expression Writer Tests', () => { }` ); + await check( + ` + model Foo { + x Boolean + } + + model Test { + foo Foo + @@deny('all', !foo.x) + } + `, + (model) => model.attributes[0].args[1].value, + `{ + NOT: { + foo: { + is: { + x: true + } + } + } + }` + ); + await check( ` model Foo { @@ -502,7 +525,7 @@ describe('Expression Writer Tests', () => { owner: { is: { id: { - equals: user.id + equals: user?.id } } } @@ -527,7 +550,7 @@ describe('Expression Writer Tests', () => { is: { id: { not: { - equals: user.id + equals: user?.id } } } @@ -552,7 +575,7 @@ describe('Expression Writer Tests', () => { owner: { is: { id: { - equals: user.id + equals: user?.id } } } diff --git a/packages/schema/tsconfig.json b/packages/schema/tsconfig.json index 63c6576dc..835023fea 100644 --- a/packages/schema/tsconfig.json +++ b/packages/schema/tsconfig.json @@ -12,7 +12,11 @@ "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "baseUrl": "./src" + "baseUrl": ".", + "paths": { + "@lang/*": ["src/language-server/*"] + }, + "resolveJsonModule": true }, "include": ["src/**/*.ts"], "exclude": ["out", "node_modules"] diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2f1d618b4..3ab4a5a7b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -44,6 +44,8 @@ importers: ts-jest: ^29.0.1 ts-morph: ^16.0.0 ts-node: ^10.9.1 + tsc-alias: ^1.7.0 + tsconfig-paths-jest: ^0.0.1 typescript: ^4.6.2 vscode-jsonrpc: ^8.0.2 vscode-languageclient: ^7.0.0 @@ -77,6 +79,8 @@ importers: tmp: 0.2.1 ts-jest: 29.0.1_poggjixajg6vd6yquly7s7dsj4 ts-node: 10.9.1_ck2axrxkiif44rdbzjywaqjysa + tsc-alias: 1.7.0 + tsconfig-paths-jest: 0.0.1 typescript: 4.8.3 samples/todo: @@ -2277,6 +2281,11 @@ packages: engines: {node: '>= 12'} dev: false + /commander/9.4.1: + resolution: {integrity: sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==} + engines: {node: ^12.20.0 || >=14} + dev: true + /commondir/1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} dev: true @@ -4351,6 +4360,11 @@ packages: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} dev: true + /mylas/2.1.13: + resolution: {integrity: sha512-+MrqnJRtxdF+xngFfUUkIMQrUUL0KsxbADUkn23Z/4ibGg192Q+z+CQyiYwvWTsYjJygmMR8+w3ZDa98Zh6ESg==} + engines: {node: '>=12.0.0'} + dev: true + /nanoid/3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -4766,6 +4780,12 @@ packages: find-up: 4.1.0 dev: true + /plimit-lit/1.4.0: + resolution: {integrity: sha512-e4VKIdzc5+vvTuNZeWDTWHCNPLZ1+jXeQ9HqZhAS+vlAodNr8A26IcTA9OudjLXj8fV+KRW/ZzsoyrTZzoWD/A==} + dependencies: + queue-lit: 1.4.0 + dev: true + /postcss-import/14.1.0_postcss@8.4.16: resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} engines: {node: '>=10.0.0'} @@ -4913,6 +4933,10 @@ packages: engines: {node: '>=6'} dev: true + /queue-lit/1.4.0: + resolution: {integrity: sha512-l1+4YHm4vHWpCnvTg8JMsnPETmPvLGWhqjvNOc8TSbqscGplHVSWXOxybA3vYeMNNIR9Z1PQt85U+S3wFJX2uQ==} + dev: true + /queue-microtask/1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -5642,6 +5666,22 @@ packages: resolution: {integrity: sha512-Bq44KCEt7JVaNLa148mBCJkcQf4l7jtLEBDuDdeuLynWDA+1a60P4D0rMkqSM9mOKLQbIWUddE9h3XKyKwBeqA==} dev: true + /tsc-alias/1.7.0: + resolution: {integrity: sha512-n/K6g8S7Ec7Y/A2Z77Ikp2Uv1S1ERtT63ni69XV4W1YPT4rnNmz8ItgIiJYvKfFnKfqcZQ81UPjoKpMTxaC/rg==} + hasBin: true + dependencies: + chokidar: 3.5.3 + commander: 9.4.1 + globby: 11.1.0 + mylas: 2.1.13 + normalize-path: 3.0.0 + plimit-lit: 1.4.0 + dev: true + + /tsconfig-paths-jest/0.0.1: + resolution: {integrity: sha512-YKhUKqbteklNppC2NqL7dv1cWF8eEobgHVD5kjF1y9Q4ocqpBiaDlYslQ9eMhtbqIPRrA68RIEXqknEjlxdwxw==} + dev: true + /tsconfig-paths/3.14.1: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} dependencies: diff --git a/samples/todo/.env b/samples/todo/.env index 23337add5..08437b40f 100644 --- a/samples/todo/.env +++ b/samples/todo/.env @@ -2,4 +2,11 @@ NEXTAUTH_URL=http://localhost:3000 GOOGLE_ID=423589857007-uioobc20f8ek0mend4g7qjck4c5a7f1s.apps.googleusercontent.com GOOGLE_SECRET=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 NEXTAUTH_SECRET=abc123 -DATABASE_URL="postgresql://postgres:abc123@localhost:5432/zenstack-todo?schema=public" +#DATABASE_URL=postgres://postgres:6aXr6Q2fqscnDHA@db.oupzipbojojlbyvaudpl.supabase.co:6543/postgres +#DATABASE_URL="postgresql://postgres:abc123@localhost:5432/todo?schema=public" + +# No Pooling +DATABASE_URL=postgresql://postgres:6aXr6Q2fqscnDHA@db.oupzipbojojlbyvaudpl.supabase.co:5432/postgres?schema=public + +# Pooling +#DATABASE_URL=postgres://postgres:6aXr6Q2fqscnDHA@db.oupzipbojojlbyvaudpl.supabase.co:6543/postgres diff --git a/samples/todo/components/AccessDenied.tsx b/samples/todo/components/AccessDenied.tsx index bb865f61c..02ec75ff2 100644 --- a/samples/todo/components/AccessDenied.tsx +++ b/samples/todo/components/AccessDenied.tsx @@ -1,11 +1,12 @@ import { signIn } from 'next-auth/react'; +import Link from 'next/link'; export default function AccessDenied() { return ( <>

Access Denied

- { e.preventDefault(); @@ -13,7 +14,7 @@ export default function AccessDenied() { }} > You must be signed in to view this page - +

); diff --git a/samples/todo/package-lock.json b/samples/todo/package-lock.json index 49d8a8654..55d4472c8 100644 --- a/samples/todo/package-lock.json +++ b/samples/todo/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "@prisma/client": "^4.4.0", "@zenstackhq/runtime": "^0.1.1", + "bcryptjs": "^2.4.3", "daisyui": "^2.31.0", "next": "12.3.1", "next-auth": "^4.10.3", @@ -923,6 +924,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "node_modules/bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + }, "node_modules/binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", @@ -4612,6 +4618,11 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + }, "binary-extensions": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", diff --git a/samples/todo/package.json b/samples/todo/package.json index 6305a6765..90ad63cd9 100644 --- a/samples/todo/package.json +++ b/samples/todo/package.json @@ -11,11 +11,12 @@ "db-push": "prisma db push --schema .zenstack/schema.prisma", "db-migrate": "prisma migrate dev --schema .zenstack/schema.prisma", "db-reset": "prisma migrate reset --schema .zenstack/schema.prisma", - "generate": "npm run --prefix ../../packages/schema build && node ../../packages/schema/bin/cli generate ./schema.zmodel --destination .zenstack" + "generate": "node ../../packages/schema/bin/cli generate ./schema.zmodel --destination .zenstack" }, "dependencies": { "@prisma/client": "^4.4.0", "@zenstackhq/runtime": "^0.1.1", + "bcryptjs": "^2.4.3", "daisyui": "^2.31.0", "next": "12.3.1", "next-auth": "^4.10.3", diff --git a/samples/todo/pages/index.tsx b/samples/todo/pages/index.tsx index ba1726189..3b3d0edfd 100644 --- a/samples/todo/pages/index.tsx +++ b/samples/todo/pages/index.tsx @@ -1,32 +1,32 @@ import type { NextPage } from 'next'; import LoginButton from '../components/LoginButton'; import { useSession } from 'next-auth/react'; -import { useTodoList } from '@zenstack/hooks'; -import { SpaceUserRole, TodoList } from '@zenstack/.prisma'; +import { useTodoCollection } from '@zenstack/hooks'; +import { SpaceUserRole, TodoCollection } from '@zenstack/.prisma'; const Home: NextPage = () => { const { data: session } = useSession(); const { - create: createTodoList, - find: findTodoList, - del: deleteTodoList, - } = useTodoList(); - const { data: todoLists } = findTodoList(); + create: createTodoCollection, + find: findTodoCollection, + del: deleteTodoCollection, + } = useTodoCollection(); + const { data: todoCollections } = findTodoCollection(); - async function onCreateTodoList() { - await createTodoList({ + async function onCreateTodoCollection() { + await createTodoCollection({ data: { - title: 'My Todo List', + title: 'My Todo Collection', ownerId: session!.user.id, spaceId: 'f0c9fc5c-e6e5-4146-a540-214f6ac5701c', }, }); } - async function onCreateFilledTodoList() { - await createTodoList({ + async function onCreateFilledTodoCollection() { + await createTodoCollection({ data: { - title: 'My Todo List', + title: 'My Todo Collection', ownerId: session!.user.id, spaceId: 'f0c9fc5c-e6e5-4146-a540-214f6ac5701c', todos: { @@ -38,20 +38,22 @@ const Home: NextPage = () => { }); } - async function onDeleteTodoList(todoList: TodoList) { - await deleteTodoList(todoList.id); + async function onDeleteTodoCollection(todoList: TodoCollection) { + await deleteTodoCollection(todoList.id); } - function renderTodoLists() { + function renderTodoCollections() { return ( <>
    - {todoLists?.map((todoList) => ( -
  • -

    {todoList.title}

    + {todoCollections?.map((collection) => ( +
  • +

    {collection.title}

    @@ -71,19 +73,22 @@ const Home: NextPage = () => { {session && ( <> -

    Todo Lists

    - {renderTodoLists()} + {renderTodoCollections()} )} diff --git a/samples/todo/schema.zmodel b/samples/todo/schema.zmodel index 71bdf6da0..392b9dea7 100644 --- a/samples/todo/schema.zmodel +++ b/samples/todo/schema.zmodel @@ -19,7 +19,7 @@ model Space { name String @length(1, 100) slug String @unique @length(1, 20) members SpaceUser[] - todoLists TodoList[] + todoCollections TodoCollection[] // require login @@deny('all', auth() == null) @@ -66,7 +66,7 @@ model User { name String? @length(1, 100) spaces SpaceUser[] image String? @url - todoLists TodoList[] + todoCollections TodoCollection[] todos Todo[] accounts Account[] sessions Session[] @@ -115,7 +115,7 @@ model VerificationToken { @@unique([identifier, token]) } -model TodoList { +model TodoCollection { id String @id @default(uuid()) createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@ -143,14 +143,15 @@ model Todo { updatedAt DateTime @updatedAt owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade) ownerId String - todoList TodoList @relation(fields: [todoListId], references: [id], onDelete: Cascade) - todoListId String + todoCollection TodoCollection @relation(fields: [todoCollectionId], references: [id], onDelete: Cascade) + todoCollectionId String title String completedAt DateTime? // require login @@deny('all', auth() == null) - // owner has full access, also space members have full access (if the parent TodoList is not private) - @@allow('all', todoList.owner == auth() || (todoList.space.members?[user == auth()] && !todoList.private)) + // owner has full access, also space members have full access (if the parent TodoCollection is not private) + @@allow('all', todoCollection.owner == auth()) + @@allow('all', todoCollection.space.members?[user == auth()] && !todoCollection.private) } From a14d53d0d889dfcd1d6efbc484f6345a5e91b2a1 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Tue, 11 Oct 2022 22:18:05 +0800 Subject: [PATCH 09/15] WIP --- packages/runtime/package.json | 3 + packages/runtime/src/handler/data-handler.ts | 117 ++ packages/runtime/src/index.ts | 3 +- packages/runtime/src/request-handler.ts | 27 + packages/runtime/src/request/index.ts | 75 + packages/runtime/src/types.ts | 27 + packages/schema/package.json | 7 +- packages/schema/src/cli/index.ts | 2 - packages/schema/src/generator/constants.ts | 1 + packages/schema/src/generator/prisma/index.ts | 184 ++- .../generator/server/data/data-generator.ts | 30 +- .../server/data/expression-writer.ts | 126 +- .../server/data/plain-expression-builder.ts | 23 +- .../server/function/function-generator.ts | 4 +- packages/schema/src/generator/server/index.ts | 4 +- .../schema/src/generator/service/index.ts | 33 + .../tests/generator/expression-writer.test.ts | 152 +- pnpm-lock.yaml | 1336 ++--------------- pnpm-workspace.yaml | 1 - samples/todo/.vscode/launch.json | 11 + samples/todo/package-lock.json | 22 +- samples/todo/package.json | 4 +- samples/todo/pages/api/zen/[...path].ts | 10 +- samples/todo/tsconfig.json | 3 +- 24 files changed, 809 insertions(+), 1396 deletions(-) create mode 100644 packages/runtime/src/handler/data-handler.ts create mode 100644 packages/runtime/src/request-handler.ts create mode 100644 packages/runtime/src/request/index.ts create mode 100644 packages/runtime/src/types.ts create mode 100644 packages/schema/src/generator/constants.ts create mode 100644 samples/todo/.vscode/launch.json diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 098a400e9..ac3397048 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -6,6 +6,7 @@ "types": "lib/index.d.ts", "scripts": { "build": "tsc", + "watch": "tsc --watch", "npm-publish": "pnpm build && pnpm publish --no-git-checks --access public" }, "keywords": [], @@ -15,9 +16,11 @@ "lib/**/*" ], "dependencies": { + "deepcopy": "^2.1.0", "swr": "^1.3.0" }, "peerDependencies": { + "next": "12.3.1", "react": "^17.0.2 || ^18", "react-dom": "^17.0.2 || ^18" }, diff --git a/packages/runtime/src/handler/data-handler.ts b/packages/runtime/src/handler/data-handler.ts new file mode 100644 index 000000000..382b9478d --- /dev/null +++ b/packages/runtime/src/handler/data-handler.ts @@ -0,0 +1,117 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import { RequestHandlerOptions } from '../request-handler'; +import { PolicyOperationKind, QueryContext, Service } from '../types'; +import deepcopy from 'deepcopy'; + +export default class DataHandler { + constructor( + private readonly service: Service, + private readonly options: RequestHandlerOptions + ) {} + + async handle(req: NextApiRequest, res: NextApiResponse, path: string[]) { + const [model, id] = path; + const method = req.method; + + const context = { user: await this.options.getServerUser(req, res) }; + + switch (method) { + case 'GET': + this.get(req, res, model, id, context); + break; + + case 'POST': + this.post(req, res, model, context); + break; + + case 'PUT': + this.put(req, res, model, id, context); + break; + + case 'DELETE': + this.del(req, res, model, id, context); + break; + } + } + + private async get( + req: NextApiRequest, + res: NextApiResponse, + model: string, + id: string, + context: QueryContext + ) { + const db = (this.service.db as any)[model]; + const args = req.query.q ? JSON.parse(req.query.q as string) : {}; + const processedArgs = this.processDbArgs(model, args, 'read', context); + + let r; + if (id) { + if (processedArgs.where) { + processedArgs.where = { + AND: [args.where, { id }], + }; + } else { + processedArgs.where = { id }; + } + r = await db.findFirst(processedArgs); + } else { + r = await db.findMany(processedArgs); + } + + this.postProcess(r); + + res.status(200).send(r); + } + + private processDbArgs( + model: string, + args: any, + action: PolicyOperationKind, + context: QueryContext + ) { + const r = deepcopy(args); + const guard = this.service.buildQueryGuard(model, action, context); + if (guard) { + if (!r.where) { + r.where = guard; + } else { + r.where = { + AND: [guard, r.where], + }; + } + } + return r; + } + + private async postProcess(r: any) {} + + private post( + req: NextApiRequest, + res: NextApiResponse, + model: string, + context: QueryContext + ) { + throw new Error('Function not implemented.'); + } + + private put( + req: NextApiRequest, + res: NextApiResponse, + model: string, + id: string, + context: QueryContext + ) { + throw new Error('Function not implemented.'); + } + + private del( + req: NextApiRequest, + res: NextApiResponse, + model: string, + id: string, + context: QueryContext + ) { + throw new Error('Function not implemented.'); + } +} diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index 56e4b0555..2e3073df3 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -1 +1,2 @@ -export * from './request'; +export * from './types'; +export * from './request-handler'; diff --git a/packages/runtime/src/request-handler.ts b/packages/runtime/src/request-handler.ts new file mode 100644 index 000000000..c86b6dee8 --- /dev/null +++ b/packages/runtime/src/request-handler.ts @@ -0,0 +1,27 @@ +import { NextApiRequest, NextApiResponse } from 'next'; +import DataHandler from './handler/data-handler'; +import { AuthUser, Service } from './types'; + +export type RequestHandlerOptions = { + getServerUser: ( + req: NextApiRequest, + res: NextApiResponse + ) => Promise; +}; + +export function RequestHandler( + service: Service, + options: RequestHandlerOptions +) { + const dataHandler = new DataHandler(service, options); + return async (req: NextApiRequest, res: NextApiResponse) => { + const [route, ...rest] = req.query.path as string[]; + switch (route) { + case 'data': + return dataHandler.handle(req, res, rest); + + default: + res.status(404).json({ error: 'Unknown route: ' + route }); + } + }; +} diff --git a/packages/runtime/src/request/index.ts b/packages/runtime/src/request/index.ts new file mode 100644 index 000000000..b62269e7b --- /dev/null +++ b/packages/runtime/src/request/index.ts @@ -0,0 +1,75 @@ +import useSWR, { useSWRConfig } from 'swr'; +import type { ScopedMutator } from 'swr/dist/types'; + +const fetcher = async (url: string, options?: RequestInit) => { + const res = await fetch(url, options); + if (!res.ok) { + const error: Error & { info?: any; status?: number } = new Error( + 'An error occurred while fetching the data.' + ); + error.info = await res.json(); + error.status = res.status; + throw error; + } + return res.json(); +}; + +function makeUrl(url: string, args: unknown) { + return args ? url + `q=${encodeURIComponent(JSON.stringify(args))}` : url; +} + +export function get(url: string, args?: unknown) { + return useSWR(makeUrl(url, args), fetcher); +} + +export async function post( + url: string, + data: Data, + mutate: ScopedMutator +) { + const r: Result = await fetcher(url, { + method: 'POST', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify(data), + }); + mutate(url); + return r; +} + +export async function put( + url: string, + data: Data, + mutate: ScopedMutator +) { + const r: Result = await fetcher(url, { + method: 'PUT', + headers: { + 'content-type': 'application/json', + }, + body: JSON.stringify(data), + }); + mutate(url, r); + return r; +} + +export async function del( + url: string, + args: unknown, + mutate: ScopedMutator +) { + const reqUrl = makeUrl(url, args); + const r: Result = await fetcher(reqUrl, { + method: 'DELETE', + }); + const path = url.split('/'); + path.pop(); + mutate(path.join('/')); + return r; +} + +export function getMutate() { + const { mutate } = useSWRConfig(); + return mutate; +} diff --git a/packages/runtime/src/types.ts b/packages/runtime/src/types.ts new file mode 100644 index 000000000..03daa50f6 --- /dev/null +++ b/packages/runtime/src/types.ts @@ -0,0 +1,27 @@ +export interface DbOperations { + findMany(args: any): Promise; + findFirst(args: any): Promise; + create(args: any): Promise; + update(args: any): Promise; + delete(args: any): Promise; +} + +export type PolicyKind = 'allow' | 'deny'; + +export type PolicyOperationKind = 'create' | 'update' | 'read' | 'delete'; + +export type AuthUser = { id: string } & Record; + +export type QueryContext = { + user?: AuthUser; +}; + +export interface Service { + get db(): DbClient; + + buildQueryGuard( + model: string, + spec: PolicyOperationKind, + context: QueryContext + ): any; +} diff --git a/packages/schema/package.json b/packages/schema/package.json index 21adae7eb..ffa1ef2e1 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -1,7 +1,7 @@ { - "name": "@zenstackhq/schema", - "displayName": "ZenStack Data Modeling Schema Language", - "description": "Please enter a brief description here", + "name": "zenstack", + "displayName": "ZenStack CLI and Language Tools", + "description": "ZenStack CLI and Language Tools", "version": "0.1.0", "engines": { "vscode": "^1.56.0" @@ -59,6 +59,7 @@ "test": "jest" }, "dependencies": { + "@zenstackhq/runtime": "workspace:0.1.1", "change-case": "^4.1.2", "chevrotain": "^9.1.0", "colors": "^1.4.0", diff --git a/packages/schema/src/cli/index.ts b/packages/schema/src/cli/index.ts index 440f8635a..c6c3a5c87 100644 --- a/packages/schema/src/cli/index.ts +++ b/packages/schema/src/cli/index.ts @@ -11,7 +11,6 @@ import PrismaGenerator from '../generator/prisma'; import ServiceGenerator from '../generator/service'; import ReactHooksGenerator from '../generator/react-hooks'; import NextAuthGenerator from '../generator/next-auth'; -import ServerGenerator from '../generator/server'; export const generateAction = async ( fileName: string, @@ -35,7 +34,6 @@ export const generateAction = async ( new PrismaGenerator(), new ServiceGenerator(), new ReactHooksGenerator(), - new ServerGenerator(), new NextAuthGenerator(), ]; diff --git a/packages/schema/src/generator/constants.ts b/packages/schema/src/generator/constants.ts new file mode 100644 index 000000000..3d59f2708 --- /dev/null +++ b/packages/schema/src/generator/constants.ts @@ -0,0 +1 @@ +export const RUNTIME_PACKAGE = '@zenstackhq/runtime'; diff --git a/packages/schema/src/generator/prisma/index.ts b/packages/schema/src/generator/prisma/index.ts index 896faf18e..3ca2a0057 100644 --- a/packages/schema/src/generator/prisma/index.ts +++ b/packages/schema/src/generator/prisma/index.ts @@ -13,6 +13,7 @@ import { Expression, InvocationExpr, isArrayExpr, + isEnum, isInvocationExpr, isLiteralExpr, isReferenceExpr, @@ -34,6 +35,12 @@ import { ModelFieldType, } from './prisma-builder'; import { execSync } from 'child_process'; +import { Project, SourceFile, VariableDeclarationKind } from 'ts-morph'; +import { RUNTIME_PACKAGE } from '../constants'; +import type { PolicyKind, PolicyOperationKind } from '@zenstackhq/runtime'; +import ExpressionWriter from '../server/data/expression-writer'; +import { extractDataModelsWithAllowRules } from '../utils'; +import { camelCase } from 'change-case'; const supportedProviders = ['postgresql', 'mysql', 'sqlite', 'sqlserver']; const supportedAttrbutes = [ @@ -48,6 +55,19 @@ const supportedAttrbutes = [ export default class PrismaGenerator implements Generator { async generate(context: Context) { + // generate prisma schema + const schemaFile = await this.generateSchema(context); + + // run prisma generate and install @prisma/client + await this.generatePrismaClient(schemaFile); + + // generate prisma query guard + await this.generateQueryGuard(context); + + console.log(colors.blue(` ✔️ Prisma schema and query code generated`)); + } + + private async generateSchema(context: Context) { const { schema } = context; const prisma = new PrismaModel(); @@ -75,22 +95,18 @@ export default class PrismaGenerator implements Generator { const outFile = path.join(context.outDir, 'schema.prisma'); await writeFile(outFile, prisma.toString()); - console.log(colors.blue(` ✔️ Prisma schema generated`)); - - // run prisma generate and install @prisma/client - await this.generatePrismaClient(outFile); + return outFile; } async generatePrismaClient(schemaFile: string) { try { - execSync('npx prisma'); + execSync('npx prisma -v'); } catch (err) { execSync(`npm i prisma @prisma/client`); console.log(colors.blue(' ✔️ Prisma package installed')); } execSync(`npx prisma generate --schema "${schemaFile}"`); - console.log(colors.blue(' ✔️ Prisma client generated')); } private isStringLiteral(node: AstNode): node is LiteralExpr { @@ -320,4 +336,160 @@ export default class PrismaGenerator implements Generator { decl.fields.map((f) => f.name) ); } + + private async generateQueryGuard(context: Context) { + const project = new Project(); + const sf = project.createSourceFile( + path.join(context.outDir, 'query/guard.ts'), + undefined, + { overwrite: true } + ); + + sf.addImportDeclaration({ + namedImports: [{ name: 'QueryContext' }], + moduleSpecifier: RUNTIME_PACKAGE, + isTypeOnly: true, + }); + + // import enums + for (const e of context.schema.declarations.filter((d) => isEnum(d))) { + sf.addImportDeclaration({ + namedImports: [{ name: e.name }], + moduleSpecifier: '../.prisma', + }); + } + + const models = extractDataModelsWithAllowRules(context.schema); + models.forEach((model) => + this.generateQueryGuardForModel(model as DataModel, sf) + ); + + sf.formatText({}); + await project.save(); + } + + private getPolicyExpressions( + model: DataModel, + kind: PolicyKind, + operation: PolicyOperationKind + ) { + const attrs = model.attributes.filter( + (attr) => attr.decl.ref?.name === kind + ); + return attrs + .filter((attr) => { + if ( + !isLiteralExpr(attr.args[0].value) || + typeof attr.args[0].value.value !== 'string' + ) { + return false; + } + const ops = attr.args[0].value.value + .split(',') + .map((s) => s.trim()); + return ops.includes(operation) || ops.includes('all'); + }) + .map((attr) => attr.args[1].value); + } + + private async generateQueryGuardForModel( + model: DataModel, + sourceFile: SourceFile + ) { + for (const kind of ['create', 'update', 'read', 'delete']) { + const func = sourceFile + .addFunction({ + name: camelCase(model.name) + '_' + kind, + returnType: 'any', + parameters: [ + { + name: 'context', + type: 'QueryContext', + }, + ], + isExported: true, + }) + .addBody(); + + func.addStatements('const { user } = context;'); + + // r = ; + func.addVariableStatement({ + declarationKind: VariableDeclarationKind.Const, + declarations: [ + { + name: 'r', + initializer: (writer) => { + const exprWriter = new ExpressionWriter(writer); + const denies = this.getPolicyExpressions( + model, + 'deny', + kind as PolicyOperationKind + ); + const allows = this.getPolicyExpressions( + model, + 'allow', + kind as PolicyOperationKind + ); + + const writeDenies = () => { + writer.conditionalWrite( + denies.length > 1, + '{ AND: [' + ); + denies.forEach((expr, i) => { + writer.block(() => { + writer.write('NOT: '); + exprWriter.write(expr); + }); + writer.conditionalWrite( + i !== denies.length - 1, + ',' + ); + }); + writer.conditionalWrite( + denies.length > 1, + ']}' + ); + }; + + const writeAllows = () => { + writer.conditionalWrite( + allows.length > 1, + '{ OR: [' + ); + allows.forEach((expr, i) => { + exprWriter.write(expr); + writer.conditionalWrite( + i !== allows.length - 1, + ',' + ); + }); + writer.conditionalWrite( + allows.length > 1, + ']}' + ); + }; + + if (allows.length > 0 && denies.length > 0) { + writer.writeLine('{ AND: ['); + writeDenies(); + writer.writeLine(','); + writeAllows(); + writer.writeLine(']}'); + } else if (denies.length > 0) { + writeDenies(); + } else if (allows.length > 0) { + writeAllows(); + } else { + writer.write('undefined'); + } + }, + }, + ], + }); + + func.addStatements('return r;'); + } + } } diff --git a/packages/schema/src/generator/server/data/data-generator.ts b/packages/schema/src/generator/server/data/data-generator.ts index 6edaf3bc3..980efe22c 100644 --- a/packages/schema/src/generator/server/data/data-generator.ts +++ b/packages/schema/src/generator/server/data/data-generator.ts @@ -45,14 +45,14 @@ export default class DataServerGenerator implements ServerCodeGenerator { ) { const content = ` import type { NextApiRequest, NextApiResponse } from 'next'; - import { RequestionHandlerOptions } from '..'; + import { RequestHandlerOptions } from '..'; ${models.map((model) => this.writeModelImport(model)).join('\n')} export default async function ( req: NextApiRequest, res: NextApiResponse, path: string[], - options: RequestionHandlerOptions + options: RequestHandlerOptions ) { const [type, ...rest] = path; switch (type) { @@ -75,12 +75,12 @@ export default class DataServerGenerator implements ServerCodeGenerator { private generateUtils(project: Project, context: Context) { const content = ` import type { NextApiRequest, NextApiResponse } from 'next'; - import { RequestionHandlerOptions } from '..'; + import { RequestHandlerOptions } from '..'; export async function getUser( req: NextApiRequest, res: NextApiResponse, - options: RequestionHandlerOptions + options: RequestHandlerOptions ) { return await options.getServerUser(req, res); } @@ -125,8 +125,8 @@ export default class DataServerGenerator implements ServerCodeGenerator { ) { const content = ` import type { NextApiRequest, NextApiResponse } from 'next'; - import type { Prisma } from '@zenstack/.prisma'; - import { RequestionHandlerOptions } from '..'; + import type { Prisma as P } from '@zenstack/.prisma'; + import { RequestHandlerOptions } from '..'; import service from '@zenstack/service'; import { getUser, notFound } from './_utils'; @@ -134,7 +134,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { req: NextApiRequest, res: NextApiResponse, path: string[], - options: RequestionHandlerOptions + options: RequestHandlerOptions ) { switch (req.method) { case 'GET': @@ -208,7 +208,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { parameters.push({ name: 'options', - type: 'RequestionHandlerOptions', + type: 'RequestHandlerOptions', }); const func = sourceFile @@ -240,7 +240,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { const func = this.generateServeFunction(sourceFile, model, 'find'); func.addStatements([ - `const query: Prisma.${model.name}FindManyArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, + `const query: P.${model.name}FindManyArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, ]); func.addVariableStatement({ @@ -248,7 +248,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { declarations: [ { name: 'args', - type: `Prisma.${model.name}FindManyArgs`, + type: `P.${model.name}FindManyArgs`, initializer: (writer) => { writer.block(() => { writer.writeLine('...query,'); @@ -276,7 +276,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { const func = this.generateServeFunction(sourceFile, model, 'get'); func.addStatements([ - `const query: Prisma.${model.name}FindFirstArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, + `const query: P.${model.name}FindFirstArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, ]); func.addVariableStatement({ @@ -284,7 +284,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { declarations: [ { name: 'args', - type: `Prisma.${model.name}FindFirstArgs`, + type: `P.${model.name}FindFirstArgs`, initializer: (writer) => { writer.block(() => { writer.writeLine('...query,'); @@ -338,7 +338,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { declarations: [ { name: 'args', - type: `Prisma.${model.name}CreateArgs`, + type: `P.${model.name}CreateArgs`, initializer: 'req.body', }, ], @@ -366,7 +366,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { declarations: [ { name: 'body', - type: `Prisma.${model.name}UpdateArgs`, + type: `P.${model.name}UpdateArgs`, initializer: 'req.body', }, ], @@ -393,7 +393,7 @@ export default class DataServerGenerator implements ServerCodeGenerator { const func = this.generateServeFunction(sourceFile, model, 'del'); func.addStatements([ - `const args: Prisma.${model.name}DeleteArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, + `const args: P.${model.name}DeleteArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, ]); // TODO: policy diff --git a/packages/schema/src/generator/server/data/expression-writer.ts b/packages/schema/src/generator/server/data/expression-writer.ts index 44cb402b7..cb2fd4586 100644 --- a/packages/schema/src/generator/server/data/expression-writer.ts +++ b/packages/schema/src/generator/server/data/expression-writer.ts @@ -6,10 +6,10 @@ import { isEnumField, isMemberAccessExpr, isReferenceExpr, + isThisExpr, LiteralExpr, MemberAccessExpr, ReferenceExpr, - ThisExpr, UnaryExpr, } from '@lang/generated/ast'; import { CodeBlockWriter } from 'ts-morph'; @@ -49,20 +49,17 @@ export default class ExpressionWriter { this.writeMemberAccess(expr as MemberAccessExpr); break; - case ThisExpr: - throw new Error('Not implemented'); - default: throw new Error(`Not implemented: ${expr.$type}`); } }; - this.writer.block(_write); + this.block(_write); } private writeReference(expr: ReferenceExpr) { if (isEnumField(expr.target.ref)) { - throw new Error('Not implemented'); + throw new Error('We should never get here'); } else { this.writer.write(`${expr.target.ref!.name}: true`); } @@ -72,7 +69,7 @@ export default class ExpressionWriter { this.writeFieldCondition( expr.operand, () => { - this.writer.block(() => { + this.block(() => { this.writer.write(`${expr.member.ref?.name}: true`); }); }, @@ -125,12 +122,17 @@ export default class ExpressionWriter { ); } - private isFieldRef(expr: Expression): expr is ReferenceExpr { + private isFieldAccess(expr: Expression): boolean { + if (isThisExpr(expr)) { + return true; + } + if (isMemberAccessExpr(expr)) { + return this.isFieldAccess(expr.operand); + } if (isReferenceExpr(expr) && isDataModelField(expr.target.ref)) { return true; - } else { - return false; } + return false; } private guard(write: () => void) { @@ -143,11 +145,8 @@ export default class ExpressionWriter { } private writeComparison(expr: BinaryExpr, operator: ComparisonOperator) { - const leftIsFieldAccess = - this.isFieldRef(expr.left) || this.isRelationFieldAccess(expr.left); - const rightIsFieldAccess = - this.isFieldRef(expr.right) || - this.isRelationFieldAccess(expr.right); + const leftIsFieldAccess = this.isFieldAccess(expr.left); + const rightIsFieldAccess = this.isFieldAccess(expr.right); if (leftIsFieldAccess && rightIsFieldAccess) { throw new GeneratorError( @@ -177,27 +176,30 @@ export default class ExpressionWriter { operator = this.negateOperator(operator); } - const type = (fieldAccess as TypedNode).$resolvedType?.decl; - this.writeFieldCondition( fieldAccess, () => { - this.writer.block(() => { - if (isDataModel(type)) { - // comparing with an object, conver to "id" comparison instead - this.writer.write('id: '); - this.writer.block(() => { + this.block( + () => { + if (this.isModelTyped(fieldAccess)) { + // comparing with an object, conver to "id" comparison instead + this.writer.write('id: '); + this.block(() => { + this.writeOperator(operator, () => { + this.plain(operand); + this.writer.write('?.id'); + }); + }); + } else { this.writeOperator(operator, () => { this.plain(operand); - this.writer.write('?.id'); }); - }); - } else { - this.writeOperator(operator, () => { - this.plain(operand); - }); - } - }); + } + }, + // "this" expression is compiled away (to .id access), so we should + // avoid generating a new layer + !isThisExpr(fieldAccess) + ); }, 'is' ); @@ -210,7 +212,7 @@ export default class ExpressionWriter { if (operator === '!=') { // wrap a 'not' this.writer.write('not: '); - this.writer.block(() => { + this.block(() => { this.writeOperator('==', writeOperand); }); } else { @@ -227,7 +229,11 @@ export default class ExpressionWriter { let selector: string; let operand: Expression | undefined; - if (isReferenceExpr(fieldAccess)) { + if (isThisExpr(fieldAccess)) { + // pass on + writeCondition(); + return; + } else if (isReferenceExpr(fieldAccess)) { selector = fieldAccess.target.ref?.name!; } else if (isMemberAccessExpr(fieldAccess)) { selector = fieldAccess.member.ref?.name!; @@ -243,26 +249,31 @@ export default class ExpressionWriter { this.writeFieldCondition( operand, () => { - this.writer.block(() => { - this.writer.write(selector + ': '); - if (this.isModelTyped(fieldAccess)) { - // expression is resolved to a model, generate relation query - this.writer.block(() => { - this.writer.write(`${relationOp}: `); + this.block( + () => { + this.writer.write(selector + ': '); + if (this.isModelTyped(fieldAccess)) { + // expression is resolved to a model, generate relation query + this.block(() => { + this.writer.write(`${relationOp}: `); + writeCondition(); + }); + } else { + // generate plain query writeCondition(); - }); - } else { - // generate plain query - writeCondition(); - } - }); + } + }, + // if operand is "this", it doesn't really generate a new layer of query, + // so we should avoid generating a new block + !isThisExpr(operand) + ); }, 'is' ); } else if (this.isModelTyped(fieldAccess)) { // reference resolved to a model, generate relation query this.writer.write(selector + ': '); - this.writer.block(() => { + this.block(() => { this.writer.write(`${relationOp}: `); writeCondition(); }); @@ -273,25 +284,16 @@ export default class ExpressionWriter { } } - private isModelTyped(expr: Expression) { - return isDataModel((expr as TypedNode).$resolvedType?.decl); - } - - private isRelationFieldAccess(expr: Expression): boolean { - if (isMemberAccessExpr(expr)) { - return this.isRelationFieldAccess(expr.operand); - } - - if ( - isReferenceExpr(expr) && - isDataModelField(expr.target.ref) && - expr.target.ref.type.reference && - isDataModel(expr.target.ref.type.reference.ref) - ) { - return true; + private block(write: () => void, condition = true) { + if (condition) { + this.writer.block(write); + } else { + write(); } + } - return false; + private isModelTyped(expr: Expression) { + return isDataModel((expr as TypedNode).$resolvedType?.decl); } mapOperator(operator: '==' | '!=' | '>' | '>=' | '<' | '<=') { diff --git a/packages/schema/src/generator/server/data/plain-expression-builder.ts b/packages/schema/src/generator/server/data/plain-expression-builder.ts index 1fe530adf..f6cd5ee60 100644 --- a/packages/schema/src/generator/server/data/plain-expression-builder.ts +++ b/packages/schema/src/generator/server/data/plain-expression-builder.ts @@ -3,10 +3,13 @@ import { ArrayExpr, Expression, InvocationExpr, + isEnumField, + isThisExpr, LiteralExpr, MemberAccessExpr, NullExpr, ReferenceExpr, + ThisExpr, } from '@lang/generated/ast'; export default class PlainExpressionBuilder { @@ -21,6 +24,9 @@ export default class PlainExpressionBuilder { case NullExpr: return this.null(); + case ThisExpr: + return this.this(expr as ThisExpr); + case ReferenceExpr: return this.reference(expr as ReferenceExpr); @@ -37,8 +43,17 @@ export default class PlainExpressionBuilder { } } + private this(expr: ThisExpr) { + // "this" is mapped to id comparison + return 'id'; + } + private memberAccess(expr: MemberAccessExpr) { - return `${this.build(expr.operand)}?.${expr.member.ref!.name}`; + if (isThisExpr(expr.operand)) { + return expr.member.ref!.name; + } else { + return `${this.build(expr.operand)}?.${expr.member.ref!.name}`; + } } private invocation(expr: InvocationExpr) { @@ -51,7 +66,11 @@ export default class PlainExpressionBuilder { } private reference(expr: ReferenceExpr) { - return expr.target.ref!.name; + if (isEnumField(expr.target.ref)) { + return `${expr.target.ref.$container.name}.${expr.target.ref.name}`; + } else { + return expr.target.ref!.name; + } } private null() { diff --git a/packages/schema/src/generator/server/function/function-generator.ts b/packages/schema/src/generator/server/function/function-generator.ts index 5f29f02f0..f83486cfb 100644 --- a/packages/schema/src/generator/server/function/function-generator.ts +++ b/packages/schema/src/generator/server/function/function-generator.ts @@ -11,13 +11,13 @@ export default class FunctionServerGenerator implements ServerCodeGenerator { private generateIndex(project: Project, context: Context) { const content = ` import type { NextApiRequest, NextApiResponse } from 'next'; - import { RequestionHandlerOptions } from '..'; + import { RequestHandlerOptions } from '..'; export default async function ( req: NextApiRequest, res: NextApiResponse, path: string[], - options: RequestionHandlerOptions + options: RequestHandlerOptions ) { throw new Error('Not implemented'); } diff --git a/packages/schema/src/generator/server/index.ts b/packages/schema/src/generator/server/index.ts index 5836d9d44..e6f7fe3e5 100644 --- a/packages/schema/src/generator/server/index.ts +++ b/packages/schema/src/generator/server/index.ts @@ -24,14 +24,14 @@ export default class ServerGenerator implements Generator { export type AuthUser = { id: string } & Record; - export type RequestionHandlerOptions = { + export type RequestHandlerOptions = { getServerUser: ( req: NextApiRequest, res: NextApiResponse ) => Promise; }; - export function RequestHandler(options: RequestionHandlerOptions) { + export function RequestHandler(options: RequestHandlerOptions) { return async (req: NextApiRequest, res: NextApiResponse) => { const [route, ...rest] = req.query.path as string[]; switch (route) { diff --git a/packages/schema/src/generator/service/index.ts b/packages/schema/src/generator/service/index.ts index b24d99b3d..e715e2cde 100644 --- a/packages/schema/src/generator/service/index.ts +++ b/packages/schema/src/generator/service/index.ts @@ -2,6 +2,7 @@ import { Context, Generator } from '../types'; import { Project, StructureKind } from 'ts-morph'; import * as path from 'path'; import colors from 'colors'; +import { RUNTIME_PACKAGE } from '../constants'; export default class ServiceGenerator implements Generator { async generate(context: Context) { @@ -17,9 +18,16 @@ export default class ServiceGenerator implements Generator { moduleSpecifier: './.prisma', }); + sf.addImportDeclaration({ + namedImports: ['Service', 'PolicyOperationKind', 'QueryContext'], + moduleSpecifier: RUNTIME_PACKAGE, + isTypeOnly: true, + }); + const cls = sf.addClass({ name: 'ZenStackService', isExported: true, + implements: ['Service'], }); cls.addMember({ kind: StructureKind.Property, @@ -33,6 +41,31 @@ export default class ServiceGenerator implements Generator { .addBody() .setBodyText('return this._prisma;'); + cls + .addMethod({ + name: 'buildQueryGuard', + isAsync: true, + parameters: [ + { + name: 'model', + type: 'string', + }, + { + name: 'operation', + type: 'PolicyOperationKind', + }, + { + name: 'context', + type: 'QueryContext', + }, + ], + }) + .addBody().setBodyText(` + const module: any = await import('./query/guard'); + const provider: (context: QueryContext) => any = module[model+ '_' + operation]; + return provider(context); + `); + sf.addStatements(['export default new ZenStackService();']); sf.formatText(); diff --git a/packages/schema/tests/generator/expression-writer.test.ts b/packages/schema/tests/generator/expression-writer.test.ts index 42fa1dd5c..dd1255a40 100644 --- a/packages/schema/tests/generator/expression-writer.test.ts +++ b/packages/schema/tests/generator/expression-writer.test.ts @@ -1,8 +1,10 @@ import { Project, VariableDeclarationKind } from 'ts-morph'; import { DataModel, + Enum, Expression, isDataModel, + isEnum, } from '../../src/language-server/generated/ast'; import { loadModel } from '../utils'; import * as tmp from 'tmp'; @@ -27,11 +29,33 @@ async function check( overwrite: true, }); + // inject user variable sf.addVariableStatement({ declarationKind: VariableDeclarationKind.Const, declarations: [{ name: 'user', initializer: '{ id: "user1" }' }], }); + // inject enums + model.declarations + .filter((d) => isEnum(d)) + .map((e) => { + sf.addVariableStatement({ + declarationKind: VariableDeclarationKind.Const, + declarations: [ + { + name: e.name, + initializer: ` + { + ${(e as Enum).fields + .map((f) => `${f.name}: "${f.name}"`) + .join(',\n')} + } + `, + }, + ], + }); + }); + sf.addVariableStatement({ declarationKind: VariableDeclarationKind.Const, declarations: [ @@ -112,6 +136,23 @@ describe('Expression Writer Tests', () => { ); }); + it('enum', async () => { + await check( + ` + enum Role { + USER + ADMIN + } + model Test { + role Role + @@allow('all', role == ADMIN) + } + `, + (model) => model.attributes[0].args[1].value, + `{ role: { equals: Role.ADMIN } }` + ); + }); + it('field against literal', async () => { await check( ` @@ -144,6 +185,55 @@ describe('Expression Writer Tests', () => { ); }); + it('this reference', async () => { + await check( + ` + model Test { + id String @id + @@allow('all', auth() == this) + } + `, + (model) => model.attributes[0].args[1].value, + `{ + id: { + equals: user?.id + } + }` + ); + + await check( + ` + model Test { + id String @id + @@deny('all', this != auth()) + } + `, + (model) => model.attributes[0].args[1].value, + `{ + id: { + not: { + equals: user?.id + } + } + }` + ); + + await check( + ` + model Test { + x Int + @@allow('all', this.x > 0) + } + `, + (model) => model.attributes[0].args[1].value, + `{ + x: { + gt: 0 + } + }` + ); + }); + it('logical', async () => { await check( ` @@ -534,52 +624,52 @@ describe('Expression Writer Tests', () => { await check( ` - model User { - id String @id - } + model User { + id String @id + } - model Test { - id String @id - owner User - @@deny('all', auth() != owner) - } - `, + model Test { + id String @id + owner User + @@deny('all', auth() != owner) + } + `, (model) => model.attributes[0].args[1].value, `{ - owner: { - is: { - id: { - not: { - equals: user?.id + owner: { + is: { + id: { + not: { + equals: user?.id + } } } } - } - }` + }` ); await check( ` - model User { - id String @id - } + model User { + id String @id + } - model Test { - id String @id - owner User - @@allow('all', auth().id == owner.id) - } - `, + model Test { + id String @id + owner User + @@allow('all', auth().id == owner.id) + } + `, (model) => model.attributes[0].args[1].value, `{ - owner: { - is: { - id: { - equals: user?.id + owner: { + is: { + id: { + equals: user?.id + } } } - } - }` + }` ); }); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3ab4a5a7b..a8704601f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,13 +7,15 @@ importers: packages/runtime: specifiers: - '@prisma/client': ^4.3.1 + deepcopy: ^2.1.0 + next: 12.3.1 react: ^17.0.2 || ^18 react-dom: ^17.0.2 || ^18 swr: ^1.3.0 typescript: ^4.6.2 dependencies: - '@prisma/client': 4.3.1 + deepcopy: 2.1.0 + next: 12.3.1_biqbaboplfbrettd7655fr4n2y react: 18.2.0 react-dom: 18.2.0_react@18.2.0 swr: 1.3.0_react@18.2.0 @@ -30,6 +32,7 @@ importers: '@types/vscode': ^1.56.0 '@typescript-eslint/eslint-plugin': ^4.14.1 '@typescript-eslint/parser': ^4.14.1 + '@zenstackhq/runtime': workspace:0.1.1 change-case: ^4.1.2 chevrotain: ^9.1.0 colors: ^1.4.0 @@ -52,6 +55,7 @@ importers: vscode-languageserver: ^7.0.0 vscode-uri: ^3.0.2 dependencies: + '@zenstackhq/runtime': link:../runtime change-case: 4.1.2 chevrotain: 9.1.0 colors: 1.4.0 @@ -83,86 +87,6 @@ importers: tsconfig-paths-jest: 0.0.1 typescript: 4.8.3 - samples/todo: - specifiers: - '@types/bcryptjs': ^2.4.2 - '@types/node': ^14.17.3 - '@types/react': 18.0.21 - '@types/react-dom': 18.0.6 - autoprefixer: ^10.4.12 - daisyui: ^2.31.0 - eslint: ^7.19.0 - eslint-config-next: 12.3.1 - next: 12.3.1 - next-auth: ^4.10.3 - postcss: ^8.4.16 - prisma: ^4.4.0 - react: 18.2.0 - react-dom: 18.2.0 - swr: ^1.3.0 - tailwindcss: ^3.1.8 - typescript: ^4.6.2 - dependencies: - daisyui: 2.31.0_jhfe3rbur6kzimvcehnoniy6fy - next: 12.3.1_biqbaboplfbrettd7655fr4n2y - next-auth: 4.10.3_biqbaboplfbrettd7655fr4n2y - prisma: 4.4.0 - react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 - swr: 1.3.0_react@18.2.0 - devDependencies: - '@types/bcryptjs': 2.4.2 - '@types/node': 14.18.29 - '@types/react': 18.0.21 - '@types/react-dom': 18.0.6 - autoprefixer: 10.4.12_postcss@8.4.16 - eslint: 7.32.0 - eslint-config-next: 12.3.1_dyxdave6dwjbccc5dgiifcmuza - postcss: 8.4.16 - tailwindcss: 3.1.8_postcss@8.4.16 - typescript: 4.8.3 - - samples/todo-target: - specifiers: - '@prisma/client': ^4.3.1 - '@types/bcryptjs': ^2.4.2 - '@types/node': ^14.17.3 - '@types/react': 18.0.21 - '@types/react-dom': 18.0.6 - autoprefixer: ^10.4.12 - daisyui: ^2.31.0 - eslint: ^7.19.0 - eslint-config-next: 12.3.1 - next: 12.3.1 - next-auth: ^4.10.3 - postcss: ^8.4.16 - prisma: ^4.3.1 - react: 18.2.0 - react-dom: 18.2.0 - swr: ^1.3.0 - tailwindcss: ^3.1.8 - typescript: ^4.6.2 - dependencies: - '@prisma/client': 4.3.1_prisma@4.4.0 - daisyui: 2.31.0_jhfe3rbur6kzimvcehnoniy6fy - next: 12.3.1_biqbaboplfbrettd7655fr4n2y - next-auth: 4.10.3_biqbaboplfbrettd7655fr4n2y - react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 - swr: 1.3.0_react@18.2.0 - devDependencies: - '@types/bcryptjs': 2.4.2 - '@types/node': 14.18.29 - '@types/react': 18.0.21 - '@types/react-dom': 18.0.6 - autoprefixer: 10.4.12_postcss@8.4.16 - eslint: 7.32.0 - eslint-config-next: 12.3.1_dyxdave6dwjbccc5dgiifcmuza - postcss: 8.4.16 - prisma: 4.4.0 - tailwindcss: 3.1.8_postcss@8.4.16 - typescript: 4.8.3 - packages: /@ampproject/remapping/2.2.0: @@ -191,8 +115,8 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/compat-data/7.19.3: - resolution: {integrity: sha512-prBHMK4JYYK+wDjJF1q99KK4JLL+egWS4nmNqdlMUgCExMZ+iZW0hGhyC3VEbsPjvaN0TBhW//VIFwBrk8sEiw==} + /@babel/compat-data/7.19.4: + resolution: {integrity: sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==} engines: {node: '>=6.9.0'} dev: true @@ -225,15 +149,15 @@ packages: dependencies: '@ampproject/remapping': 2.2.0 '@babel/code-frame': 7.18.6 - '@babel/generator': 7.19.3 + '@babel/generator': 7.19.5 '@babel/helper-compilation-targets': 7.19.3_@babel+core@7.19.3 '@babel/helper-module-transforms': 7.19.0 - '@babel/helpers': 7.19.0 - '@babel/parser': 7.19.3 + '@babel/helpers': 7.19.4 + '@babel/parser': 7.19.4 '@babel/template': 7.18.10 - '@babel/traverse': 7.19.3 - '@babel/types': 7.19.3 - convert-source-map: 1.8.0 + '@babel/traverse': 7.19.4 + '@babel/types': 7.19.4 + convert-source-map: 1.9.0 debug: 4.3.4 gensync: 1.0.0-beta.2 json5: 2.2.1 @@ -251,11 +175,11 @@ packages: jsesc: 2.5.2 dev: true - /@babel/generator/7.19.3: - resolution: {integrity: sha512-fqVZnmp1ncvZU757UzDheKZpfPgatqY59XtW2/j/18H7u76akb8xqvjw82f+i2UKd/ksYsSick/BCLQUUtJ/qQ==} + /@babel/generator/7.19.5: + resolution: {integrity: sha512-DxbNz9Lz4aMZ99qPpO1raTbcrI1ZeYh+9NR9qhfkQIbFtVEqotHojEBxHzmxhVONkGt6VyrqVQcgpefMy9pqcg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.19.3 + '@babel/types': 7.19.4 '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 dev: true @@ -279,7 +203,7 @@ packages: peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.19.3 + '@babel/compat-data': 7.19.4 '@babel/core': 7.19.3 '@babel/helper-validator-option': 7.18.6 browserslist: 4.21.4 @@ -353,6 +277,11 @@ packages: engines: {node: '>=6.9.0'} dev: true + /@babel/helper-string-parser/7.19.4: + resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} + engines: {node: '>=6.9.0'} + dev: true + /@babel/helper-validator-identifier/7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} @@ -374,6 +303,17 @@ packages: - supports-color dev: true + /@babel/helpers/7.19.4: + resolution: {integrity: sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.18.10 + '@babel/traverse': 7.19.4 + '@babel/types': 7.19.4 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/highlight/7.18.6: resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} engines: {node: '>=6.9.0'} @@ -391,12 +331,12 @@ packages: '@babel/types': 7.19.0 dev: true - /@babel/parser/7.19.3: - resolution: {integrity: sha512-pJ9xOlNWHiy9+FuFP09DEAFbAn4JskgRsVcc169w2xRBC3FRGuQEwjeIMMND9L2zc0iEhO/tGv4Zq+km+hxNpQ==} + /@babel/parser/7.19.4: + resolution: {integrity: sha512-qpVT7gtuOLjWeDTKLkJ6sryqLliBaFpAtGeqw5cs5giLldvh+Ch0plqnUMKoVAUS6ZEueQQiZV+p5pxtPitEsA==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.19.3 + '@babel/types': 7.19.4 dev: true /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.19.1: @@ -528,20 +468,6 @@ packages: '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/runtime-corejs3/7.19.1: - resolution: {integrity: sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==} - engines: {node: '>=6.9.0'} - dependencies: - core-js-pure: 3.25.2 - regenerator-runtime: 0.13.9 - dev: true - - /@babel/runtime/7.19.0: - resolution: {integrity: sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==} - engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.13.9 - /@babel/template/7.18.10: resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==} engines: {node: '>=6.9.0'} @@ -569,18 +495,18 @@ packages: - supports-color dev: true - /@babel/traverse/7.19.3: - resolution: {integrity: sha512-qh5yf6149zhq2sgIXmwjnsvmnNQC2iw70UFjp4olxucKrWd/dvlUsBI88VSLUsnMNF7/vnOiA+nk1+yLoCqROQ==} + /@babel/traverse/7.19.4: + resolution: {integrity: sha512-w3K1i+V5u2aJUOXBFFC5pveFLmtq1s3qcdDNC2qRI6WPBQIDaKFqXxDEqDO/h1dQ3HjsZoZMyIy6jGLq0xtw+g==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/generator': 7.19.3 + '@babel/generator': 7.19.5 '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-function-name': 7.19.0 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.19.3 - '@babel/types': 7.19.3 + '@babel/parser': 7.19.4 + '@babel/types': 7.19.4 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: @@ -605,6 +531,15 @@ packages: to-fast-properties: 2.0.0 dev: true + /@babel/types/7.19.4: + resolution: {integrity: sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.19.4 + '@babel/helper-validator-identifier': 7.19.1 + to-fast-properties: 2.0.0 + dev: true + /@bcoe/v8-coverage/0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} dev: true @@ -898,7 +833,7 @@ packages: dependencies: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.14 - '@jridgewell/trace-mapping': 0.3.15 + '@jridgewell/trace-mapping': 0.3.16 dev: true /@jridgewell/resolve-uri/3.1.0: @@ -922,6 +857,13 @@ packages: '@jridgewell/sourcemap-codec': 1.4.14 dev: true + /@jridgewell/trace-mapping/0.3.16: + resolution: {integrity: sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==} + dependencies: + '@jridgewell/resolve-uri': 3.1.0 + '@jridgewell/sourcemap-codec': 1.4.14 + dev: true + /@jridgewell/trace-mapping/0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: @@ -933,12 +875,6 @@ packages: resolution: {integrity: sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==} dev: false - /@next/eslint-plugin-next/12.3.1: - resolution: {integrity: sha512-sw+lTf6r6P0j+g/n9y4qdWWI2syPqZx+uc0+B/fRENqfR3KpSid6MIKqc9gNwGhJASazEQ5b3w8h4cAET213jw==} - dependencies: - glob: 7.1.7 - dev: true - /@next/swc-android-arm-eabi/12.3.1: resolution: {integrity: sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ==} engines: {node: '>= 10'} @@ -1117,37 +1053,6 @@ packages: engines: {node: '>=14'} dev: true - /@panva/hkdf/1.0.2: - resolution: {integrity: sha512-MSAs9t3Go7GUkMhpKC44T58DJ5KGk2vBo+h1cqQeqlMfdGkxaVB78ZWpv9gYi/g2fa4sopag9gJsNvS8XGgWJA==} - dev: false - - /@prisma/client/4.3.1: - resolution: {integrity: sha512-FA0/d1VMJNWqzU7WVWTNWJ+lGOLR9JUBnF73GdIPAEVo/6dWk4gHx0EmgeU+SMv4MZoxgOeTBJF2azhg7x0hMw==} - engines: {node: '>=14.17'} - requiresBuild: true - peerDependencies: - prisma: '*' - peerDependenciesMeta: - prisma: - optional: true - dependencies: - '@prisma/engines-version': 4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b - dev: false - - /@prisma/client/4.3.1_prisma@4.4.0: - resolution: {integrity: sha512-FA0/d1VMJNWqzU7WVWTNWJ+lGOLR9JUBnF73GdIPAEVo/6dWk4gHx0EmgeU+SMv4MZoxgOeTBJF2azhg7x0hMw==} - engines: {node: '>=14.17'} - requiresBuild: true - peerDependencies: - prisma: '*' - peerDependenciesMeta: - prisma: - optional: true - dependencies: - '@prisma/engines-version': 4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b - prisma: 4.4.0 - dev: false - /@prisma/debug/4.4.0: resolution: {integrity: sha512-tpJqrvmA8VlQuaVAmkFzIU7Of6xk3kQ2DYV6bPJukDZ6xmnufT27EpU8TSIra4jGdzz7y/R0rxmuXSBp24ew5w==} dependencies: @@ -1179,13 +1084,10 @@ packages: - supports-color dev: true - /@prisma/engines-version/4.3.0-32.c875e43600dfe042452e0b868f7a48b817b9640b: - resolution: {integrity: sha512-8yWpXkQRmiSfsi2Wb/ZS5D3RFbeu/btL9Pm/gdF4phB0Lo5KGsDFMxFMgaD64mwED2nHc8ZaEJg/+4Jymb9Znw==} - dev: false - /@prisma/engines/4.4.0: resolution: {integrity: sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==} requiresBuild: true + dev: true /@prisma/fetch-engine/4.4.0: resolution: {integrity: sha512-3a+f/HPvJl9XYj8IuX57/rHM8cYZuqS+R+jXx/ZPRwvELVlvVeE81GTTSMvtXguyfHXgKW7wKjiJqZm7tGw/WA==} @@ -1287,10 +1189,6 @@ packages: resolution: {integrity: sha512-Hc2i5nfAt3nLDUkQNWJcKFJaA9Avd5zz6t85w9SW7P0vGtFXScQ+xIu6znbULr9bc0pgTWejY1We2u/7EMxHWw==} dev: true - /@rushstack/eslint-patch/1.2.0: - resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==} - dev: true - /@sinclair/typebox/0.24.42: resolution: {integrity: sha512-d+2AtrHGyWek2u2ITF0lHRIv6Tt7X0dEHW+0rP+5aDCEjC3fiN2RBjrLD0yU0at52BcZbRGxLbAtXiR0hFCjYw==} dev: true @@ -1372,10 +1270,6 @@ packages: '@babel/types': 7.19.0 dev: true - /@types/bcryptjs/2.4.2: - resolution: {integrity: sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==} - dev: true - /@types/cross-spawn/6.0.2: resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==} dependencies: @@ -1421,10 +1315,6 @@ packages: resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} dev: true - /@types/json5/0.0.29: - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - dev: true - /@types/ms/0.7.31: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} dev: true @@ -1445,32 +1335,10 @@ packages: resolution: {integrity: sha512-RI1L7N4JnW5gQw2spvL7Sllfuf1SaHdrZpCHiBlCXjIlufi1SMNnbu2teze3/QE67Fg2tBlH7W+mi4hVNk4p0A==} dev: true - /@types/prop-types/15.7.5: - resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==} - dev: true - - /@types/react-dom/18.0.6: - resolution: {integrity: sha512-/5OFZgfIPSwy+YuIBP/FgJnQnsxhZhjjrnxudMddeblOouIodEQ75X14Rr4wGSG/bknL+Omy9iWlLo1u/9GzAA==} - dependencies: - '@types/react': 18.0.21 - dev: true - - /@types/react/18.0.21: - resolution: {integrity: sha512-7QUCOxvFgnD5Jk8ZKlUAhVcRj7GuJRjnjjiY/IUBWKgOlnvDvTMLD4RTF7NPyVmbRhNrbomZiOepg7M/2Kj1mA==} - dependencies: - '@types/prop-types': 15.7.5 - '@types/scheduler': 0.16.2 - csstype: 3.1.1 - dev: true - /@types/retry/0.12.0: resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} dev: true - /@types/scheduler/0.16.2: - resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} - dev: true - /@types/stack-utils/2.0.1: resolution: {integrity: sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==} dev: true @@ -1561,26 +1429,6 @@ packages: - supports-color dev: true - /@typescript-eslint/parser/5.38.0_dyxdave6dwjbccc5dgiifcmuza: - resolution: {integrity: sha512-/F63giJGLDr0ms1Cr8utDAxP2SPiglaD6V+pCOcG35P2jCqdfR7uuEhz1GIC3oy4hkUF8xA1XSXmd9hOh/a5EA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/scope-manager': 5.38.0 - '@typescript-eslint/types': 5.38.0 - '@typescript-eslint/typescript-estree': 5.38.0_typescript@4.8.3 - debug: 4.3.4 - eslint: 7.32.0 - typescript: 4.8.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/scope-manager/4.33.0: resolution: {integrity: sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ==} engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} @@ -1589,24 +1437,11 @@ packages: '@typescript-eslint/visitor-keys': 4.33.0 dev: true - /@typescript-eslint/scope-manager/5.38.0: - resolution: {integrity: sha512-ByhHIuNyKD9giwkkLqzezZ9y5bALW8VNY6xXcP+VxoH4JBDKjU5WNnsiD4HJdglHECdV+lyaxhvQjTUbRboiTA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.38.0 - '@typescript-eslint/visitor-keys': 5.38.0 - dev: true - /@typescript-eslint/types/4.33.0: resolution: {integrity: sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ==} engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} dev: true - /@typescript-eslint/types/5.38.0: - resolution: {integrity: sha512-HHu4yMjJ7i3Cb+8NUuRCdOGu2VMkfmKyIJsOr9PfkBVYLYrtMCK/Ap50Rpov+iKpxDTfnqvDbuPLgBE5FwUNfA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /@typescript-eslint/typescript-estree/4.33.0_typescript@4.8.3: resolution: {integrity: sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA==} engines: {node: ^10.12.0 || >=12.0.0} @@ -1628,27 +1463,6 @@ packages: - supports-color dev: true - /@typescript-eslint/typescript-estree/5.38.0_typescript@4.8.3: - resolution: {integrity: sha512-6P0RuphkR+UuV7Avv7MU3hFoWaGcrgOdi8eTe1NwhMp2/GjUJoODBTRWzlHpZh6lFOaPmSvgxGlROa0Sg5Zbyg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.38.0 - '@typescript-eslint/visitor-keys': 5.38.0 - debug: 4.3.4 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.3.7 - tsutils: 3.21.0_typescript@4.8.3 - typescript: 4.8.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/visitor-keys/4.33.0: resolution: {integrity: sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg==} engines: {node: ^8.10.0 || ^10.13.0 || >=11.10.1} @@ -1657,14 +1471,6 @@ packages: eslint-visitor-keys: 2.1.0 dev: true - /@typescript-eslint/visitor-keys/5.38.0: - resolution: {integrity: sha512-MxnrdIyArnTi+XyFLR+kt/uNAcdOnmT+879os7qDRI+EYySR4crXJq9BXPfRzzLGq0wgxkwidrCJ9WCAoacm1w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.38.0 - eslint-visitor-keys: 3.3.0 - dev: true - /acorn-jsx/5.3.2_acorn@7.4.1: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1673,17 +1479,6 @@ packages: acorn: 7.4.1 dev: true - /acorn-node/1.8.2: - resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==} - dependencies: - acorn: 7.4.1 - acorn-walk: 7.2.0 - xtend: 4.0.2 - - /acorn-walk/7.2.0: - resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} - engines: {node: '>=0.4.0'} - /acorn-walk/8.2.0: resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==} engines: {node: '>=0.4.0'} @@ -1693,6 +1488,7 @@ packages: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} engines: {node: '>=0.4.0'} hasBin: true + dev: true /acorn/8.8.0: resolution: {integrity: sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==} @@ -1777,6 +1573,7 @@ packages: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 + dev: true /archiver-utils/2.1.0: resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==} @@ -1813,6 +1610,7 @@ packages: /arg/5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + dev: true /argparse/1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -1820,54 +1618,11 @@ packages: sprintf-js: 1.0.3 dev: true - /aria-query/4.2.2: - resolution: {integrity: sha512-o/HelwhuKpTj/frsOsbNLNgnNGVIFsVP/SW2BSF14gVl7kAfMOJ6/8wUAUvG1R1NHKrfG+2sHZTu0yauT1qBrA==} - engines: {node: '>=6.0'} - dependencies: - '@babel/runtime': 7.19.0 - '@babel/runtime-corejs3': 7.19.1 - dev: true - - /array-includes/3.1.5: - resolution: {integrity: sha512-iSDYZMMyTPkiFasVqfuAQnWAYcvO/SeBSCGKePoEthjp4LEMTe4uLc7b025o4jAZpHhihh8xPo99TNWUWWkGDQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - get-intrinsic: 1.1.3 - is-string: 1.0.7 - dev: true - /array-union/2.1.0: resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} engines: {node: '>=8'} dev: true - /array.prototype.flat/1.3.0: - resolution: {integrity: sha512-12IUEkHsAhA4DY5s0FPgNXIdc8VRSqD9Zp78a5au9abH/SOBrsp082JOWFNTjkMozh8mqcdiKuaLGhPeYztxSw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - es-shim-unscopables: 1.0.0 - dev: true - - /array.prototype.flatmap/1.3.0: - resolution: {integrity: sha512-PZC9/8TKAIxcWKdyeb77EzULHPrIX/tIZebLJUQOMR1OwYosT8yggdfWScfTBCDj5utONvOuPQQumYsU2ULbkg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - es-shim-unscopables: 1.0.0 - dev: true - - /ast-types-flow/0.0.7: - resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} - dev: true - /astral-regex/2.0.0: resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} engines: {node: '>=8'} @@ -1882,30 +1637,6 @@ packages: engines: {node: '>= 4.0.0'} dev: true - /autoprefixer/10.4.12_postcss@8.4.16: - resolution: {integrity: sha512-WrCGV9/b97Pa+jtwf5UGaRjgQIg7OK3D06GnoYoZNcG1Xb8Gt3EfuKjlhh9i/VtT16g6PYjZ69jdJ2g8FxSC4Q==} - engines: {node: ^10 || ^12 || >=14} - hasBin: true - peerDependencies: - postcss: ^8.1.0 - dependencies: - browserslist: 4.21.4 - caniuse-lite: 1.0.30001409 - fraction.js: 4.2.0 - normalize-range: 0.1.2 - picocolors: 1.0.0 - postcss: 8.4.16 - postcss-value-parser: 4.2.0 - - /axe-core/4.4.3: - resolution: {integrity: sha512-32+ub6kkdhhWick/UjvEwRchgoetXqTK14INLqbGm5U2TzBkBNF3nQtLYm8ovxSkQWArjEQvftCKryjZaATu3w==} - engines: {node: '>=4'} - dev: true - - /axobject-query/2.2.0: - resolution: {integrity: sha512-Td525n+iPOOyUQIeBfcASuG6uJsDOITl7Mds5gFyerkWiX7qhUTdYUBlSgNMyVqtSJqwpt1kXGLdUt6SykLMRA==} - dev: true - /babel-jest/29.0.3_@babel+core@7.19.1: resolution: {integrity: sha512-ApPyHSOhS/sVzwUOQIWJmdvDhBsMG01HX9z7ogtkp1TToHGGUWFlnXJUIzCgKPSfiYLn3ibipCYzsKSURHEwLg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -1988,6 +1719,7 @@ packages: /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} + dev: true /bl/4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -2023,6 +1755,7 @@ packages: electron-to-chromium: 1.4.257 node-releases: 2.0.6 update-browserslist-db: 1.0.9_browserslist@4.21.4 + dev: true /bs-logger/0.2.6: resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} @@ -2052,13 +1785,6 @@ packages: ieee754: 1.2.1 dev: true - /call-bind/1.0.2: - resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} - dependencies: - function-bind: 1.1.1 - get-intrinsic: 1.1.3 - dev: true - /callsites/3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} @@ -2071,10 +1797,6 @@ packages: tslib: 2.4.0 dev: false - /camelcase-css/2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} - /camelcase/5.3.1: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} @@ -2169,6 +1891,7 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.2 + dev: true /ci-info/3.3.0: resolution: {integrity: sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw==} @@ -2244,6 +1967,7 @@ packages: engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 + dev: true /color-name/1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} @@ -2251,21 +1975,7 @@ packages: /color-name/1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - /color-string/1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - dev: false - - /color/4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - dev: false + dev: true /colors/1.4.0: resolution: {integrity: sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==} @@ -2333,14 +2043,8 @@ packages: safe-buffer: 5.1.2 dev: true - /cookie/0.4.2: - resolution: {integrity: sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==} - engines: {node: '>= 0.6'} - dev: false - - /core-js-pure/3.25.2: - resolution: {integrity: sha512-ItD7YpW1cUB4jaqFLZXe1AXkyqIxz6GqPnsDV4uF4hVcWh/WAGIqSqw5p0/WdsILM0Xht9s3Koyw05R3K6RtiA==} - requiresBuild: true + /convert-source-map/1.9.0: + resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} dev: true /core-util-is/1.0.3: @@ -2379,69 +2083,11 @@ packages: engines: {node: '>=8'} dev: true - /css-selector-tokenizer/0.8.0: - resolution: {integrity: sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==} - dependencies: - cssesc: 3.0.0 - fastparse: 1.1.2 - dev: false - - /cssesc/3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - - /csstype/3.1.1: - resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} - dev: true - - /daisyui/2.31.0_jhfe3rbur6kzimvcehnoniy6fy: - resolution: {integrity: sha512-qepRXgQPLNcJ8ZPZy+dUvsC7mRWvMLRcVMe85/wZA60Tnhm/bkidhOzdllL8aAk2JX+W/xlIsTJ8NZFpPm+eyw==} - peerDependencies: - autoprefixer: ^10.0.2 - postcss: ^8.1.6 - dependencies: - autoprefixer: 10.4.12_postcss@8.4.16 - color: 4.2.3 - css-selector-tokenizer: 0.8.0 - postcss: 8.4.16 - postcss-js: 4.0.0_postcss@8.4.16 - tailwindcss: 3.1.8_postcss@8.4.16 - transitivePeerDependencies: - - ts-node - dev: false - - /damerau-levenshtein/1.0.8: - resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - dev: true - /date-fns/2.29.3: resolution: {integrity: sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA==} engines: {node: '>=0.11'} dev: true - /debug/2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.0.0 - dev: true - - /debug/3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.3 - dev: true - /debug/4.3.4: resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} engines: {node: '>=6.0'} @@ -2462,6 +2108,12 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true + /deepcopy/2.1.0: + resolution: {integrity: sha512-8cZeTb1ZKC3bdSCP6XOM1IsTczIO73fdqtwa2B0N15eAz7gmyhQo+mc5gnFuulsgN3vIQYmTgbmQVKalH1dKvQ==} + dependencies: + type-detect: 4.0.8 + dev: false + /deepmerge/4.2.2: resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} engines: {node: '>=0.10.0'} @@ -2473,17 +2125,6 @@ packages: clone: 1.0.4 dev: true - /define-properties/1.1.4: - resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} - engines: {node: '>= 0.4'} - dependencies: - has-property-descriptors: 1.0.0 - object-keys: 1.1.1 - dev: true - - /defined/1.0.0: - resolution: {integrity: sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==} - /del/6.1.1: resolution: {integrity: sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg==} engines: {node: '>=10'} @@ -2503,18 +2144,6 @@ packages: engines: {node: '>=8'} dev: true - /detective/5.2.1: - resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==} - engines: {node: '>=0.8.0'} - hasBin: true - dependencies: - acorn-node: 1.8.2 - defined: 1.0.0 - minimist: 1.2.6 - - /didyoumean/1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - /diff-sequences/29.0.0: resolution: {integrity: sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} @@ -2532,16 +2161,6 @@ packages: path-type: 4.0.0 dev: true - /dlv/1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - - /doctrine/2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} - dependencies: - esutils: 2.0.3 - dev: true - /doctrine/3.0.0: resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} engines: {node: '>=6.0.0'} @@ -2563,6 +2182,7 @@ packages: /electron-to-chromium/1.4.257: resolution: {integrity: sha512-C65sIwHqNnPC2ADMfse/jWTtmhZMII+x6ADI9gENzrOiI7BpxmfKFE84WkIEl5wEg+7+SfIkwChDlsd1Erju2A==} + dev: true /emittery/0.10.2: resolution: {integrity: sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==} @@ -2573,10 +2193,6 @@ packages: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true - /emoji-regex/9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: true - /end-of-stream/1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} dependencies: @@ -2601,54 +2217,10 @@ packages: is-arrayish: 0.2.1 dev: true - /es-abstract/1.20.3: - resolution: {integrity: sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - es-to-primitive: 1.2.1 - function-bind: 1.1.1 - function.prototype.name: 1.1.5 - get-intrinsic: 1.1.3 - get-symbol-description: 1.0.0 - has: 1.0.3 - has-property-descriptors: 1.0.0 - has-symbols: 1.0.3 - internal-slot: 1.0.3 - is-callable: 1.2.6 - is-negative-zero: 2.0.2 - is-regex: 1.1.4 - is-shared-array-buffer: 1.0.2 - is-string: 1.0.7 - is-weakref: 1.0.2 - object-inspect: 1.12.2 - object-keys: 1.1.1 - object.assign: 4.1.4 - regexp.prototype.flags: 1.4.3 - safe-regex-test: 1.0.0 - string.prototype.trimend: 1.0.5 - string.prototype.trimstart: 1.0.5 - unbox-primitive: 1.0.2 - dev: true - - /es-shim-unscopables/1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} - dependencies: - has: 1.0.3 - dev: true - - /es-to-primitive/1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} - dependencies: - is-callable: 1.2.6 - is-date-object: 1.0.5 - is-symbol: 1.0.4 - dev: true - /escalade/3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} + dev: true /escape-string-regexp/1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} @@ -2665,170 +2237,6 @@ packages: engines: {node: '>=10'} dev: true - /eslint-config-next/12.3.1_dyxdave6dwjbccc5dgiifcmuza: - resolution: {integrity: sha512-EN/xwKPU6jz1G0Qi6Bd/BqMnHLyRAL0VsaQaWA7F3KkjAgZHi4f1uL1JKGWNxdQpHTW/sdGONBd0bzxUka/DJg==} - peerDependencies: - eslint: ^7.23.0 || ^8.0.0 - typescript: '>=3.3.1' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@next/eslint-plugin-next': 12.3.1 - '@rushstack/eslint-patch': 1.2.0 - '@typescript-eslint/parser': 5.38.0_dyxdave6dwjbccc5dgiifcmuza - eslint: 7.32.0 - eslint-import-resolver-node: 0.3.6 - eslint-import-resolver-typescript: 2.7.1_hpmu7kn6tcn2vnxpfzvv33bxmy - eslint-plugin-import: 2.26.0_eslint@7.32.0 - eslint-plugin-jsx-a11y: 6.6.1_eslint@7.32.0 - eslint-plugin-react: 7.31.8_eslint@7.32.0 - eslint-plugin-react-hooks: 4.6.0_eslint@7.32.0 - typescript: 4.8.3 - transitivePeerDependencies: - - eslint-import-resolver-webpack - - supports-color - dev: true - - /eslint-import-resolver-node/0.3.6: - resolution: {integrity: sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==} - dependencies: - debug: 3.2.7 - resolve: 1.22.1 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-import-resolver-typescript/2.7.1_hpmu7kn6tcn2vnxpfzvv33bxmy: - resolution: {integrity: sha512-00UbgGwV8bSgUv34igBDbTOtKhqoRMy9bFjNehT40bXg6585PNIct8HhXZ0SybqB9rWtXj9crcku8ndDn/gIqQ==} - engines: {node: '>=4'} - peerDependencies: - eslint: '*' - eslint-plugin-import: '*' - dependencies: - debug: 4.3.4 - eslint: 7.32.0 - eslint-plugin-import: 2.26.0_eslint@7.32.0 - glob: 7.2.3 - is-glob: 4.0.3 - resolve: 1.22.1 - tsconfig-paths: 3.14.1 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-module-utils/2.7.4_gw5q3jyuku4zrugqrckhwmprvm: - resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - debug: 3.2.7 - eslint: 7.32.0 - eslint-import-resolver-node: 0.3.6 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-plugin-import/2.26.0_eslint@7.32.0: - resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - dependencies: - array-includes: 3.1.5 - array.prototype.flat: 1.3.0 - debug: 2.6.9 - doctrine: 2.1.0 - eslint: 7.32.0 - eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4_gw5q3jyuku4zrugqrckhwmprvm - has: 1.0.3 - is-core-module: 2.10.0 - is-glob: 4.0.3 - minimatch: 3.1.2 - object.values: 1.1.5 - resolve: 1.22.1 - tsconfig-paths: 3.14.1 - transitivePeerDependencies: - - eslint-import-resolver-typescript - - eslint-import-resolver-webpack - - supports-color - dev: true - - /eslint-plugin-jsx-a11y/6.6.1_eslint@7.32.0: - resolution: {integrity: sha512-sXgFVNHiWffBq23uiS/JaP6eVR622DqwB4yTzKvGZGcPq6/yZ3WmOZfuBks/vHWo9GaFOqC2ZK4i6+C35knx7Q==} - engines: {node: '>=4.0'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - dependencies: - '@babel/runtime': 7.19.0 - aria-query: 4.2.2 - array-includes: 3.1.5 - ast-types-flow: 0.0.7 - axe-core: 4.4.3 - axobject-query: 2.2.0 - damerau-levenshtein: 1.0.8 - emoji-regex: 9.2.2 - eslint: 7.32.0 - has: 1.0.3 - jsx-ast-utils: 3.3.3 - language-tags: 1.0.5 - minimatch: 3.1.2 - semver: 6.3.0 - dev: true - - /eslint-plugin-react-hooks/4.6.0_eslint@7.32.0: - resolution: {integrity: sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 - dependencies: - eslint: 7.32.0 - dev: true - - /eslint-plugin-react/7.31.8_eslint@7.32.0: - resolution: {integrity: sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - dependencies: - array-includes: 3.1.5 - array.prototype.flatmap: 1.3.0 - doctrine: 2.1.0 - eslint: 7.32.0 - estraverse: 5.3.0 - jsx-ast-utils: 3.3.3 - minimatch: 3.1.2 - object.entries: 1.1.5 - object.fromentries: 2.0.5 - object.hasown: 1.1.1 - object.values: 1.1.5 - prop-types: 15.8.1 - resolve: 2.0.0-next.4 - semver: 6.3.0 - string.prototype.matchall: 4.0.7 - dev: true - /eslint-scope/5.1.1: resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} engines: {node: '>=8.0.0'} @@ -2864,11 +2272,6 @@ packages: engines: {node: '>=10'} dev: true - /eslint-visitor-keys/3.3.0: - resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /eslint/7.32.0: resolution: {integrity: sha512-VHZ8gX+EDfz+97jGcgyGCyRia/dPOd6Xh9yPv8Bl1+SoaIwD+a/vlrOmGRUyOYu7MwUhc7CxqeaDZU13S4+EpA==} engines: {node: ^10.12.0 || >=12.0.0} @@ -3019,10 +2422,6 @@ packages: resolution: {integrity: sha512-WvJe06IfNYlr+6cO3uQkdKdy3Cb1LlCJSF8zRs2eT8yuhdbSlR9nIt+TgQ92RUxiRrQm+/S7RARnMfCs5iuAjw==} dev: true - /fastparse/1.1.2: - resolution: {integrity: sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==} - dev: false - /fastq/1.13.0: resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} dependencies: @@ -3088,9 +2487,6 @@ packages: resolution: {integrity: sha512-8m0XvW8kZbfnJOA4NvSVXu95mLbPf4LQGwQyqVukIYS4KzSNJiyKSmuZUmbVHteUi6MGkAJGPb0goPZqI+Tsqg==} dev: true - /fraction.js/4.2.0: - resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} - /fs-constants/1.0.0: resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} dev: true @@ -3129,29 +2525,17 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true + dev: true optional: true /function-bind/1.1.1: resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - - /function.prototype.name/1.1.5: - resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - functions-have-names: 1.2.3 dev: true /functional-red-black-tree/1.0.1: resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} dev: true - /functions-have-names/1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - dev: true - /gensync/1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} @@ -3162,14 +2546,6 @@ packages: engines: {node: 6.* || 8.* || >= 10.*} dev: true - /get-intrinsic/1.1.3: - resolution: {integrity: sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==} - dependencies: - function-bind: 1.1.1 - has: 1.0.3 - has-symbols: 1.0.3 - dev: true - /get-package-type/0.1.0: resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} engines: {node: '>=8.0.0'} @@ -3180,37 +2556,12 @@ packages: engines: {node: '>=10'} dev: true - /get-symbol-description/1.0.0: - resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 - dev: true - /glob-parent/5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 - /glob-parent/6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - dependencies: - is-glob: 4.0.3 - - /glob/7.1.7: - resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - /glob/7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} dependencies: @@ -3257,10 +2608,6 @@ packages: resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} dev: true - /has-bigints/1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - dev: true - /has-flag/3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} @@ -3271,24 +2618,6 @@ packages: engines: {node: '>=8'} dev: true - /has-property-descriptors/1.0.0: - resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} - dependencies: - get-intrinsic: 1.1.3 - dev: true - - /has-symbols/1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - dev: true - - /has-tostringtag/1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} - engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.0.3 - dev: true - /has-yarn/2.1.0: resolution: {integrity: sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==} engines: {node: '>=8'} @@ -3299,6 +2628,7 @@ packages: engines: {node: '>= 0.4.0'} dependencies: function-bind: 1.1.1 + dev: true /hasha/5.2.2: resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} @@ -3406,58 +2736,21 @@ packages: engines: {node: '>=10'} dev: true - /internal-slot/1.0.3: - resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} - engines: {node: '>= 0.4'} - dependencies: - get-intrinsic: 1.1.3 - has: 1.0.3 - side-channel: 1.0.4 - dev: true - /is-arrayish/0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} dev: true - /is-arrayish/0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - dev: false - - /is-bigint/1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} - dependencies: - has-bigints: 1.0.2 - dev: true - /is-binary-path/2.1.0: resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 - - /is-boolean-object/1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 - dev: true - - /is-callable/1.2.6: - resolution: {integrity: sha512-krO72EO2NptOGAX2KYyqbP9vYMlNAXdB53rq6f8LXY6RY7JdSR/3BD6wLUlPHSAesmY9vstNrjvqGaCiRK/91Q==} - engines: {node: '>= 0.4'} dev: true /is-core-module/2.10.0: resolution: {integrity: sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==} dependencies: has: 1.0.3 - - /is-date-object/1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 dev: true /is-docker/2.2.1: @@ -3491,18 +2784,6 @@ packages: engines: {node: '>=8'} dev: true - /is-negative-zero/2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} - engines: {node: '>= 0.4'} - dev: true - - /is-number-object/1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 - dev: true - /is-number/7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} @@ -3517,50 +2798,16 @@ packages: engines: {node: '>=8'} dev: true - /is-regex/1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - has-tostringtag: 1.0.0 - dev: true - - /is-shared-array-buffer/1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} - dependencies: - call-bind: 1.0.2 - dev: true - /is-stream/2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} dev: true - /is-string/1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} - dependencies: - has-tostringtag: 1.0.0 - dev: true - - /is-symbol/1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.0.3 - dev: true - /is-unicode-supported/0.1.0: resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} engines: {node: '>=10'} dev: true - /is-weakref/1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} - dependencies: - call-bind: 1.0.2 - dev: true - /is-windows/1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} @@ -4075,10 +3322,6 @@ packages: - ts-node dev: true - /jose/4.9.3: - resolution: {integrity: sha512-f8E/z+T3Q0kA9txzH2DKvH/ds2uggcw0m3vVPSB9HrSkrQ7mojjifvS7aR8cw+lQl2Fcmx9npwaHpM/M3GD8UQ==} - dev: false - /js-tokens/4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -4112,13 +3355,6 @@ packages: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true - /json5/1.0.1: - resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} - hasBin: true - dependencies: - minimist: 1.2.6 - dev: true - /json5/2.2.1: resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==} engines: {node: '>=6'} @@ -4137,14 +3373,6 @@ packages: resolution: {integrity: sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==} dev: true - /jsx-ast-utils/3.3.3: - resolution: {integrity: sha512-fYQHZTZ8jSfmWZ0iyzfwiU4WDX4HpHbMCZ3gPlWYiCl3BoeOTsqKBqnTVfH2rYT7eP5c3sVbeSPHnnJOaTrWiw==} - engines: {node: '>=4.0'} - dependencies: - array-includes: 3.1.5 - object.assign: 4.1.4 - dev: true - /kleur/3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} @@ -4172,16 +3400,6 @@ packages: vscode-languageserver-textdocument: 1.0.7 vscode-uri: 3.0.6 - /language-subtag-registry/0.3.22: - resolution: {integrity: sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==} - dev: true - - /language-tags/1.0.5: - resolution: {integrity: sha512-qJhlO9cGXi6hBGKoxEG/sKZDAHD5Hnu9Hs4WbOY3pCWXDhw0N8x1NenNzm2EnNLkLkk7J2SdxAkDSbb6ftT+UQ==} - dependencies: - language-subtag-registry: 0.3.22 - dev: true - /lazystream/1.0.1: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} @@ -4202,10 +3420,6 @@ packages: type-check: 0.4.0 dev: true - /lilconfig/2.0.6: - resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==} - engines: {node: '>=10'} - /lines-and-columns/1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true @@ -4273,6 +3487,7 @@ packages: hasBin: true dependencies: js-tokens: 4.0.0 + dev: false /lower-case/2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} @@ -4339,19 +3554,12 @@ packages: dependencies: brace-expansion: 2.0.1 - /minimist/1.2.6: - resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} - /mkdirp/1.0.4: resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} engines: {node: '>=10'} hasBin: true dev: false - /ms/2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - dev: true - /ms/2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} dev: true @@ -4369,6 +3577,7 @@ packages: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + dev: false /natural-compare/1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -4379,30 +3588,6 @@ packages: engines: {node: '>=10'} dev: true - /next-auth/4.10.3_biqbaboplfbrettd7655fr4n2y: - resolution: {integrity: sha512-7zc4aXYc/EEln7Pkcsn21V1IevaTZsMLJwapfbnKA4+JY0+jFzWbt5p/ljugesGIrN4VOZhpZIw50EaFZyghJQ==} - engines: {node: ^12.19.0 || ^14.15.0 || ^16.13.0} - peerDependencies: - nodemailer: ^6.6.5 - react: ^17.0.2 || ^18 - react-dom: ^17.0.2 || ^18 - peerDependenciesMeta: - nodemailer: - optional: true - dependencies: - '@babel/runtime': 7.19.0 - '@panva/hkdf': 1.0.2 - cookie: 0.4.2 - jose: 4.9.3 - oauth: 0.9.15 - openid-client: 5.1.9 - preact: 10.11.0 - preact-render-to-string: 5.2.4_preact@10.11.0 - react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 - uuid: 8.3.2 - dev: false - /next/12.3.1_biqbaboplfbrettd7655fr4n2y: resolution: {integrity: sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==} engines: {node: '>=12.22.0'} @@ -4473,6 +3658,7 @@ packages: /node-releases/2.0.6: resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} + dev: true /normalize-package-data/2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -4486,10 +3672,7 @@ packages: /normalize-path/3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - - /normalize-range/0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} + dev: true /npm-run-path/4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} @@ -4498,82 +3681,6 @@ packages: path-key: 3.1.1 dev: true - /oauth/0.9.15: - resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==} - dev: false - - /object-assign/4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - dev: true - - /object-hash/2.2.0: - resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} - engines: {node: '>= 6'} - dev: false - - /object-hash/3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} - - /object-inspect/1.12.2: - resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} - dev: true - - /object-keys/1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - dev: true - - /object.assign/4.1.4: - resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - has-symbols: 1.0.3 - object-keys: 1.1.1 - dev: true - - /object.entries/1.1.5: - resolution: {integrity: sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - dev: true - - /object.fromentries/2.0.5: - resolution: {integrity: sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - dev: true - - /object.hasown/1.1.1: - resolution: {integrity: sha512-LYLe4tivNQzq4JdaWW6WO3HMZZJWzkkH8fnI6EebWl0VZth2wL2Lovm74ep2/gZzlaTdV62JZHEqHQ2yVn8Q/A==} - dependencies: - define-properties: 1.1.4 - es-abstract: 1.20.3 - dev: true - - /object.values/1.1.5: - resolution: {integrity: sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - dev: true - - /oidc-token-hash/5.0.1: - resolution: {integrity: sha512-EvoOtz6FIEBzE+9q253HsLCVRiK/0doEJ2HCvvqMQb3dHZrP3WlJKYtJ55CRTw4jmYomzH4wkPuCj/I3ZvpKxQ==} - engines: {node: ^10.13.0 || >=12.0.0} - dev: false - /once/1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} dependencies: @@ -4595,16 +3702,6 @@ packages: is-wsl: 2.2.0 dev: true - /openid-client/5.1.9: - resolution: {integrity: sha512-o/11Xos2fRPpK1zQrPfSIhIusFrAkqGSPwkD0UlUB+CCuRzd7zrrBJwIjgnVv3VUSif9ZGXh2d3GSJNH2Koh5g==} - engines: {node: ^12.19.0 || ^14.15.0 || ^16.13.0} - dependencies: - jose: 4.9.3 - lru-cache: 6.0.0 - object-hash: 2.2.0 - oidc-token-hash: 5.0.1 - dev: false - /optionator/0.9.1: resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} engines: {node: '>= 0.8.0'} @@ -4751,6 +3848,7 @@ packages: /path-parse/1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + dev: true /path-type/4.0.0: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} @@ -4764,10 +3862,6 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - /pify/2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} - /pirates/4.0.5: resolution: {integrity: sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==} engines: {node: '>= 6'} @@ -4786,61 +3880,6 @@ packages: queue-lit: 1.4.0 dev: true - /postcss-import/14.1.0_postcss@8.4.16: - resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} - engines: {node: '>=10.0.0'} - peerDependencies: - postcss: ^8.0.0 - dependencies: - postcss: 8.4.16 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.1 - - /postcss-js/4.0.0_postcss@8.4.16: - resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.3.3 - dependencies: - camelcase-css: 2.0.1 - postcss: 8.4.16 - - /postcss-load-config/3.1.4_postcss@8.4.16: - resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} - engines: {node: '>= 10'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - dependencies: - lilconfig: 2.0.6 - postcss: 8.4.16 - yaml: 1.10.2 - - /postcss-nested/5.0.6_postcss@8.4.16: - resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.2.14 - dependencies: - postcss: 8.4.16 - postcss-selector-parser: 6.0.10 - - /postcss-selector-parser/6.0.10: - resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} - engines: {node: '>=4'} - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - - /postcss-value-parser/4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - /postcss/8.4.14: resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} engines: {node: ^10 || ^12 || >=14} @@ -4850,27 +3889,6 @@ packages: source-map-js: 1.0.2 dev: false - /postcss/8.4.16: - resolution: {integrity: sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.4 - picocolors: 1.0.0 - source-map-js: 1.0.2 - - /preact-render-to-string/5.2.4_preact@10.11.0: - resolution: {integrity: sha512-iIPHb3BXUQ3Za6KNhkjN/waq11Oh+QWWtAgN3id3LrL+cszH3DYh8TxJPNQ6Aogsbu4JsqdJLBZltwPFpG6N6w==} - peerDependencies: - preact: '>=10' - dependencies: - preact: 10.11.0 - pretty-format: 3.8.0 - dev: false - - /preact/10.11.0: - resolution: {integrity: sha512-Fk6+vB2kb6mSJfDgODq0YDhMfl0HNtK5+Uc9QqECO4nlyPAQwCI+BKyWO//idA7ikV7o+0Fm6LQmNuQi1wXI1w==} - dev: false - /prelude-ls/1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} @@ -4885,18 +3903,6 @@ packages: react-is: 18.2.0 dev: true - /pretty-format/3.8.0: - resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} - dev: false - - /prisma/4.4.0: - resolution: {integrity: sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==} - engines: {node: '>=14.17'} - hasBin: true - requiresBuild: true - dependencies: - '@prisma/engines': 4.4.0 - /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: true @@ -4920,14 +3926,6 @@ packages: sisteransi: 1.0.5 dev: true - /prop-types/15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - dependencies: - loose-envify: 1.4.0 - object-assign: 4.1.1 - react-is: 16.13.1 - dev: true - /punycode/2.1.1: resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} engines: {node: '>=6'} @@ -4940,10 +3938,6 @@ packages: /queue-microtask/1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - /quick-lru/5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} - /react-dom/18.2.0_react@18.2.0: resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==} peerDependencies: @@ -4954,10 +3948,6 @@ packages: scheduler: 0.23.0 dev: false - /react-is/16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - dev: true - /react-is/18.2.0: resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} dev: true @@ -4969,11 +3959,6 @@ packages: loose-envify: 1.4.0 dev: false - /read-cache/1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} - dependencies: - pify: 2.3.0 - /read-pkg-up/7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} engines: {node: '>=8'} @@ -5025,22 +4010,11 @@ packages: engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 - - /regenerator-runtime/0.13.9: - resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} + dev: true /regexp-to-ast/0.5.0: resolution: {integrity: sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==} - /regexp.prototype.flags/1.4.3: - resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} - engines: {node: '>= 0.4'} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - functions-have-names: 1.2.3 - dev: true - /regexpp/3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} @@ -5090,14 +4064,6 @@ packages: is-core-module: 2.10.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - - /resolve/2.0.0-next.4: - resolution: {integrity: sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ==} - hasBin: true - dependencies: - is-core-module: 2.10.0 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 dev: true /restore-cursor/3.1.0: @@ -5143,14 +4109,6 @@ packages: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} dev: true - /safe-regex-test/1.0.0: - resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 - is-regex: 1.1.4 - dev: true - /scheduler/0.23.0: resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==} dependencies: @@ -5198,24 +4156,10 @@ packages: resolution: {integrity: sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==} dev: true - /side-channel/1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} - dependencies: - call-bind: 1.0.2 - get-intrinsic: 1.1.3 - object-inspect: 1.12.2 - dev: true - /signal-exit/3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} dev: true - /simple-swizzle/0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - dependencies: - is-arrayish: 0.3.2 - dev: false - /sisteransi/1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} dev: true @@ -5253,6 +4197,7 @@ packages: /source-map-js/1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} + dev: false /source-map-support/0.5.13: resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} @@ -5320,35 +4265,6 @@ packages: strip-ansi: 6.0.1 dev: true - /string.prototype.matchall/4.0.7: - resolution: {integrity: sha512-f48okCX7JiwVi1NXCVWcFnZgADDC/n2vePlQ/KUCNqCikLLilQvwjMO8+BHVKvgzH0JB0J9LEPgxOGT02RoETg==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - get-intrinsic: 1.1.3 - has-symbols: 1.0.3 - internal-slot: 1.0.3 - regexp.prototype.flags: 1.4.3 - side-channel: 1.0.4 - dev: true - - /string.prototype.trimend/1.0.5: - resolution: {integrity: sha512-I7RGvmjV4pJ7O3kdf+LXFpVfdNOxtCW/2C8f6jNiW4+PQchwxkCDzlk1/7p+Wl4bqFIZeF47qAHXLuHHWKAxog==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - dev: true - - /string.prototype.trimstart/1.0.5: - resolution: {integrity: sha512-THx16TJCGlsN0o6dl2o6ncWUsdgnLRSA23rRE5pyGBw/mLr3Ej/R2LaqCtgP8VNMGZsvMWnf9ooZPyY2bHvUFg==} - dependencies: - call-bind: 1.0.2 - define-properties: 1.1.4 - es-abstract: 1.20.3 - dev: true - /string_decoder/1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} dependencies: @@ -5368,11 +4284,6 @@ packages: ansi-regex: 5.0.1 dev: true - /strip-bom/3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - dev: true - /strip-bom/4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} engines: {node: '>=8'} @@ -5443,6 +4354,7 @@ packages: /supports-preserve-symlinks-flag/1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} + dev: true /swr/1.3.0_react@18.2.0: resolution: {integrity: sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==} @@ -5463,38 +4375,6 @@ packages: strip-ansi: 6.0.1 dev: true - /tailwindcss/3.1.8_postcss@8.4.16: - resolution: {integrity: sha512-YSneUCZSFDYMwk+TGq8qYFdCA3yfBRdBlS7txSq0LUmzyeqRe3a8fBQzbz9M3WS/iFT4BNf/nmw9mEzrnSaC0g==} - engines: {node: '>=12.13.0'} - hasBin: true - peerDependencies: - postcss: ^8.0.9 - dependencies: - arg: 5.0.2 - chokidar: 3.5.3 - color-name: 1.1.4 - detective: 5.2.1 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.2.12 - glob-parent: 6.0.2 - is-glob: 4.0.3 - lilconfig: 2.0.6 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.0.0 - postcss: 8.4.16 - postcss-import: 14.1.0_postcss@8.4.16 - postcss-js: 4.0.0_postcss@8.4.16 - postcss-load-config: 3.1.4_postcss@8.4.16 - postcss-nested: 5.0.6_postcss@8.4.16 - postcss-selector-parser: 6.0.10 - postcss-value-parser: 4.2.0 - quick-lru: 5.1.1 - resolve: 1.22.1 - transitivePeerDependencies: - - ts-node - /tar-stream/2.2.0: resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} engines: {node: '>=6'} @@ -5682,15 +4562,6 @@ packages: resolution: {integrity: sha512-YKhUKqbteklNppC2NqL7dv1cWF8eEobgHVD5kjF1y9Q4ocqpBiaDlYslQ9eMhtbqIPRrA68RIEXqknEjlxdwxw==} dev: true - /tsconfig-paths/3.14.1: - resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} - dependencies: - '@types/json5': 0.0.29 - json5: 1.0.1 - minimist: 1.2.6 - strip-bom: 3.0.0 - dev: true - /tslib/1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true @@ -5718,7 +4589,6 @@ packages: /type-detect/4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} - dev: true /type-fest/0.16.0: resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} @@ -5751,15 +4621,6 @@ packages: hasBin: true dev: true - /unbox-primitive/1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} - dependencies: - call-bind: 1.0.2 - has-bigints: 1.0.2 - has-symbols: 1.0.3 - which-boxed-primitive: 1.0.2 - dev: true - /undici/5.10.0: resolution: {integrity: sha512-c8HsD3IbwmjjbLvoZuRI26TZic+TSEe8FPMLLOkN1AfYRhdjnKBU6yL+IwcSCbdZiX4e5t0lfMDLDCqj4Sq70g==} engines: {node: '>=12.18'} @@ -5786,6 +4647,7 @@ packages: browserslist: 4.21.4 escalade: 3.1.1 picocolors: 1.0.0 + dev: true /upper-case-first/2.0.2: resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} @@ -5815,6 +4677,7 @@ packages: /util-deprecate/1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: true /uuid/3.4.0: resolution: {integrity: sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==} @@ -5825,6 +4688,7 @@ packages: /uuid/8.3.2: resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} hasBin: true + dev: true /v8-compile-cache-lib/3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -5916,16 +4780,6 @@ packages: resolution: {integrity: sha512-5cZ7mecD3eYcMiCH4wtRPA5iFJZ50BJYDfckI5RRpQiktMiYTcn0ccLTZOvcbBume+1304fQztxeNzNS9Gvrnw==} dev: false - /which-boxed-primitive/1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} - dependencies: - is-bigint: 1.0.4 - is-boolean-object: 1.1.2 - is-number-object: 1.0.7 - is-string: 1.0.7 - is-symbol: 1.0.4 - dev: true - /which/2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -5960,10 +4814,6 @@ packages: signal-exit: 3.0.7 dev: true - /xtend/4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - /y18n/5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -5972,10 +4822,6 @@ packages: /yallist/4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - /yaml/1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} - engines: {node: '>= 6'} - /yargs-parser/21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 51d360569..9a36b4056 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,2 @@ packages: - 'packages/*' - - 'samples/*' diff --git a/samples/todo/.vscode/launch.json b/samples/todo/.vscode/launch.json new file mode 100644 index 000000000..e3d8e6e92 --- /dev/null +++ b/samples/todo/.vscode/launch.json @@ -0,0 +1,11 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Next.js: debug server-side", + "type": "node-terminal", + "request": "launch", + "command": "npm run dev" + } + ] +} diff --git a/samples/todo/package-lock.json b/samples/todo/package-lock.json index 55d4472c8..9c038bcb4 100644 --- a/samples/todo/package-lock.json +++ b/samples/todo/package-lock.json @@ -9,7 +9,7 @@ "version": "0.1.0", "dependencies": { "@prisma/client": "^4.4.0", - "@zenstackhq/runtime": "^0.1.1", + "@zenstackhq/runtime": "file:../../packages/runtime/lib", "bcryptjs": "^2.4.3", "daisyui": "^2.31.0", "next": "12.3.1", @@ -31,6 +31,7 @@ "typescript": "^4.6.2" } }, + "../../packages/runtime/lib": {}, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -655,16 +656,8 @@ } }, "node_modules/@zenstackhq/runtime": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@zenstackhq/runtime/-/runtime-0.1.1.tgz", - "integrity": "sha512-QsgMjOu5BZKcCPOSZVP32bqHjL1YeUNlarzygqZkMpKK89yZTpqYvrG2VGIUOLj3ESvkn0Cr+D7OlzsE8ZayOA==", - "dependencies": { - "swr": "^1.3.0" - }, - "peerDependencies": { - "react": "^17.0.2 || ^18", - "react-dom": "^17.0.2 || ^18" - } + "resolved": "../../packages/runtime/lib", + "link": true }, "node_modules/acorn": { "version": "7.4.1", @@ -4432,12 +4425,7 @@ } }, "@zenstackhq/runtime": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@zenstackhq/runtime/-/runtime-0.1.1.tgz", - "integrity": "sha512-QsgMjOu5BZKcCPOSZVP32bqHjL1YeUNlarzygqZkMpKK89yZTpqYvrG2VGIUOLj3ESvkn0Cr+D7OlzsE8ZayOA==", - "requires": { - "swr": "^1.3.0" - } + "version": "file:../../packages/runtime/lib" }, "acorn": { "version": "7.4.1", diff --git a/samples/todo/package.json b/samples/todo/package.json index 90ad63cd9..b6dd75a75 100644 --- a/samples/todo/package.json +++ b/samples/todo/package.json @@ -15,14 +15,14 @@ }, "dependencies": { "@prisma/client": "^4.4.0", - "@zenstackhq/runtime": "^0.1.1", "bcryptjs": "^2.4.3", "daisyui": "^2.31.0", "next": "12.3.1", "next-auth": "^4.10.3", "react": "18.2.0", "react-dom": "18.2.0", - "swr": "^1.3.0" + "swr": "^1.3.0", + "@zenstackhq/runtime": "file:../../packages/runtime/lib" }, "devDependencies": { "@types/bcryptjs": "^2.4.2", diff --git a/samples/todo/pages/api/zen/[...path].ts b/samples/todo/pages/api/zen/[...path].ts index 6930e427f..fe6d8bbaa 100644 --- a/samples/todo/pages/api/zen/[...path].ts +++ b/samples/todo/pages/api/zen/[...path].ts @@ -1,12 +1,16 @@ -import { RequestHandler, RequestionHandlerOptions } from '@zenstack/server'; import { NextApiRequest, NextApiResponse } from 'next'; +import { + type RequestHandlerOptions, + RequestHandler, +} from '@zenstackhq/runtime'; import { authOptions } from '@api/auth/[...nextauth]'; import { unstable_getServerSession } from 'next-auth'; +import service from '@zenstack/service'; -const options: RequestionHandlerOptions = { +const options: RequestHandlerOptions = { async getServerUser(req: NextApiRequest, res: NextApiResponse) { const session = await unstable_getServerSession(req, res, authOptions); return session?.user; }, }; -export default RequestHandler(options); +export default RequestHandler(service, options); diff --git a/samples/todo/tsconfig.json b/samples/todo/tsconfig.json index 854c3c712..d65ace5ca 100644 --- a/samples/todo/tsconfig.json +++ b/samples/todo/tsconfig.json @@ -20,8 +20,7 @@ "@lib/*": ["lib/*"], "@components/*": ["lib/components/*"], "@components": ["lib/components/index"], - "@zenstack/*": [".zenstack/*"], - "@zenstack": [".zenstack/index"] + "@zenstack/*": [".zenstack/*"] } }, "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"], From cc306b47a5748d8c1d840f699d124dafb919f026 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Wed, 12 Oct 2022 11:44:02 +0800 Subject: [PATCH 10/15] WIP --- packages/runtime/jest.config.ts | 32 ++ packages/runtime/package.json | 8 + .../{data-handler.ts => data/handler.ts} | 56 ++-- .../src/handler/data/query-processor.ts | 54 +++ packages/runtime/src/handler/index.ts | 1 + packages/runtime/src/handler/types.ts | 9 + packages/runtime/src/request-handler.ts | 2 +- packages/runtime/src/types.ts | 8 +- packages/runtime/tests/coverage/clover.xml | 63 ++++ .../tests/coverage/coverage-final.json | 2 + .../tests/coverage/lcov-report/base.css | 224 +++++++++++++ .../coverage/lcov-report/block-navigation.js | 87 +++++ .../tests/coverage/lcov-report/favicon.png | Bin 0 -> 445 bytes .../tests/coverage/lcov-report/index.html | 116 +++++++ .../tests/coverage/lcov-report/prettify.css | 1 + .../tests/coverage/lcov-report/prettify.js | 2 + .../lcov-report/query-processor.ts.html | 247 ++++++++++++++ .../lcov-report/sort-arrow-sprite.png | Bin 0 -> 138 bytes .../tests/coverage/lcov-report/sorter.js | 196 +++++++++++ packages/runtime/tests/coverage/lcov.info | 83 +++++ .../runtime/tests/query-processor.test.ts | 170 ++++++++++ packages/runtime/tsconfig.json | 6 +- packages/schema/.gitignore | 1 + packages/schema/jest.config.ts | 26 +- packages/schema/src/generator/constants.ts | 1 + packages/schema/src/generator/prisma/index.ts | 54 ++- .../schema/src/generator/react-hooks/index.ts | 6 +- .../schema/src/generator/service/index.ts | 20 ++ packages/schema/src/utils/indent-string.ts | 41 +-- .../tests/generator/expression-writer.test.ts | 9 +- .../tests/generator/prisma-builder.test.ts | 1 - pnpm-lock.yaml | 311 ++++++------------ 32 files changed, 1514 insertions(+), 323 deletions(-) create mode 100644 packages/runtime/jest.config.ts rename packages/runtime/src/handler/{data-handler.ts => data/handler.ts} (72%) create mode 100644 packages/runtime/src/handler/data/query-processor.ts create mode 100644 packages/runtime/src/handler/index.ts create mode 100644 packages/runtime/src/handler/types.ts create mode 100644 packages/runtime/tests/coverage/clover.xml create mode 100644 packages/runtime/tests/coverage/coverage-final.json create mode 100644 packages/runtime/tests/coverage/lcov-report/base.css create mode 100644 packages/runtime/tests/coverage/lcov-report/block-navigation.js create mode 100644 packages/runtime/tests/coverage/lcov-report/favicon.png create mode 100644 packages/runtime/tests/coverage/lcov-report/index.html create mode 100644 packages/runtime/tests/coverage/lcov-report/prettify.css create mode 100644 packages/runtime/tests/coverage/lcov-report/prettify.js create mode 100644 packages/runtime/tests/coverage/lcov-report/query-processor.ts.html create mode 100644 packages/runtime/tests/coverage/lcov-report/sort-arrow-sprite.png create mode 100644 packages/runtime/tests/coverage/lcov-report/sorter.js create mode 100644 packages/runtime/tests/coverage/lcov.info create mode 100644 packages/runtime/tests/query-processor.test.ts diff --git a/packages/runtime/jest.config.ts b/packages/runtime/jest.config.ts new file mode 100644 index 000000000..5fde9b5bf --- /dev/null +++ b/packages/runtime/jest.config.ts @@ -0,0 +1,32 @@ +/* + * For a detailed explanation regarding each configuration property and type check, visit: + * https://jestjs.io/docs/configuration + */ + +import tsconfig from './tsconfig.json'; +const moduleNameMapper = require('tsconfig-paths-jest')(tsconfig); + +export default { + // Automatically clear mock calls, instances, contexts and results before every test + clearMocks: true, + + // Indicates whether the coverage information should be collected while executing the test + collectCoverage: true, + + // The directory where Jest should output its coverage files + coverageDirectory: 'tests/coverage', + + // An array of regexp pattern strings used to skip coverage collection + coveragePathIgnorePatterns: ['/node_modules/', '/tests/'], + + // Indicates which provider should be used to instrument code for coverage + coverageProvider: 'v8', + + // A list of reporter names that Jest uses when writing coverage reports + coverageReporters: ['json', 'text', 'lcov', 'clover'], + + // A map from regular expressions to paths to transformers + transform: { '^.+\\.tsx?$': 'ts-jest' }, + + moduleNameMapper, +}; diff --git a/packages/runtime/package.json b/packages/runtime/package.json index ac3397048..049dbfcf5 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -7,6 +7,7 @@ "scripts": { "build": "tsc", "watch": "tsc --watch", + "test": "jest", "npm-publish": "pnpm build && pnpm publish --no-git-checks --access public" }, "keywords": [], @@ -25,6 +26,13 @@ "react-dom": "^17.0.2 || ^18" }, "devDependencies": { + "@types/jest": "^29.0.3", + "@types/node": "^14.18.29", + "jest": "^29.0.3", + "ts-jest": "^29.0.1", + "ts-node": "^10.9.1", + "tsc-alias": "^1.7.0", + "tsconfig-paths-jest": "^0.0.1", "typescript": "^4.6.2" } } diff --git a/packages/runtime/src/handler/data-handler.ts b/packages/runtime/src/handler/data/handler.ts similarity index 72% rename from packages/runtime/src/handler/data-handler.ts rename to packages/runtime/src/handler/data/handler.ts index 382b9478d..419e2bdd6 100644 --- a/packages/runtime/src/handler/data-handler.ts +++ b/packages/runtime/src/handler/data/handler.ts @@ -1,13 +1,18 @@ import { NextApiRequest, NextApiResponse } from 'next'; -import { RequestHandlerOptions } from '../request-handler'; -import { PolicyOperationKind, QueryContext, Service } from '../types'; -import deepcopy from 'deepcopy'; +import { RequestHandlerOptions } from '../../request-handler'; +import { QueryContext, Service } from '../../types'; +import { RequestHandler } from '../types'; +import { QueryProcessor } from './query-processor'; + +export default class DataHandler implements RequestHandler { + private readonly queryProcessor: QueryProcessor; -export default class DataHandler { constructor( private readonly service: Service, private readonly options: RequestHandlerOptions - ) {} + ) { + this.queryProcessor = new QueryProcessor(service); + } async handle(req: NextApiRequest, res: NextApiResponse, path: string[]) { const [model, id] = path; @@ -43,7 +48,12 @@ export default class DataHandler { ) { const db = (this.service.db as any)[model]; const args = req.query.q ? JSON.parse(req.query.q as string) : {}; - const processedArgs = this.processDbArgs(model, args, 'read', context); + const processedArgs = await this.queryProcessor.processQueryArgs( + model, + args, + 'read', + context + ); let r; if (id) { @@ -55,37 +65,25 @@ export default class DataHandler { processedArgs.where = { id }; } r = await db.findFirst(processedArgs); + if (!r) { + res.status(404).send({ error: `${model} not found` }); + return; + } } else { r = await db.findMany(processedArgs); } - this.postProcess(r); + await this.queryProcessor.postProcess( + model, + processedArgs, + r, + 'read', + context + ); res.status(200).send(r); } - private processDbArgs( - model: string, - args: any, - action: PolicyOperationKind, - context: QueryContext - ) { - const r = deepcopy(args); - const guard = this.service.buildQueryGuard(model, action, context); - if (guard) { - if (!r.where) { - r.where = guard; - } else { - r.where = { - AND: [guard, r.where], - }; - } - } - return r; - } - - private async postProcess(r: any) {} - private post( req: NextApiRequest, res: NextApiResponse, diff --git a/packages/runtime/src/handler/data/query-processor.ts b/packages/runtime/src/handler/data/query-processor.ts new file mode 100644 index 000000000..c49e807b1 --- /dev/null +++ b/packages/runtime/src/handler/data/query-processor.ts @@ -0,0 +1,54 @@ +import deepcopy from 'deepcopy'; +import { PolicyOperationKind, QueryContext, Service } from '../../types'; + +export class QueryProcessor { + constructor(private readonly service: Service) {} + + async processQueryArgs( + model: string, + args: any, + operation: PolicyOperationKind, + context: QueryContext + ) { + const r = args ? deepcopy(args) : {}; + const guard = this.service.buildQueryGuard(model, operation, context); + if (guard) { + if (!r.where) { + r.where = guard; + } else { + r.where = { + AND: [guard, r.where], + }; + } + } + + if (r.include || r.select) { + // "include" and "select" are mutually exclusive + const selector = r.include ? 'include' : 'select'; + for (const [field, value] of Object.entries(r[selector])) { + const fieldInfo = await this.service.resolveField(model, field); + if (fieldInfo && fieldInfo.isArray) { + // note that Prisma only allows to attach filter for "to-many" relation + // query, so we need to handle "to-one" filter separately in post-processing + const fieldGuard = await this.processQueryArgs( + fieldInfo.type, + value === true ? {} : value, + operation, + context + ); + r[selector][field] = fieldGuard; + } + } + } + + return r; + } + + async postProcess( + model: string, + queryArgs: any, + data: any, + operation: PolicyOperationKind, + context: QueryContext + ) {} +} diff --git a/packages/runtime/src/handler/index.ts b/packages/runtime/src/handler/index.ts new file mode 100644 index 000000000..a73009277 --- /dev/null +++ b/packages/runtime/src/handler/index.ts @@ -0,0 +1 @@ +export { default as DataHandler } from './data/handler'; diff --git a/packages/runtime/src/handler/types.ts b/packages/runtime/src/handler/types.ts new file mode 100644 index 000000000..3d9f75e1d --- /dev/null +++ b/packages/runtime/src/handler/types.ts @@ -0,0 +1,9 @@ +import { NextApiRequest, NextApiResponse } from 'next'; + +export interface RequestHandler { + handle( + req: NextApiRequest, + res: NextApiResponse, + path: string[] + ): Promise; +} diff --git a/packages/runtime/src/request-handler.ts b/packages/runtime/src/request-handler.ts index c86b6dee8..85fb11566 100644 --- a/packages/runtime/src/request-handler.ts +++ b/packages/runtime/src/request-handler.ts @@ -1,5 +1,5 @@ import { NextApiRequest, NextApiResponse } from 'next'; -import DataHandler from './handler/data-handler'; +import { DataHandler } from './handler'; import { AuthUser, Service } from './types'; export type RequestHandlerOptions = { diff --git a/packages/runtime/src/types.ts b/packages/runtime/src/types.ts index 03daa50f6..bdcb2f770 100644 --- a/packages/runtime/src/types.ts +++ b/packages/runtime/src/types.ts @@ -16,12 +16,16 @@ export type QueryContext = { user?: AuthUser; }; -export interface Service { +export type FieldInfo = { type: string; isArray: boolean }; + +export interface Service { get db(): DbClient; + resolveField(model: string, field: string): Promise; + buildQueryGuard( model: string, - spec: PolicyOperationKind, + operation: PolicyOperationKind, context: QueryContext ): any; } diff --git a/packages/runtime/tests/coverage/clover.xml b/packages/runtime/tests/coverage/clover.xml new file mode 100644 index 000000000..1e2768eb0 --- /dev/null +++ b/packages/runtime/tests/coverage/clover.xml @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/runtime/tests/coverage/coverage-final.json b/packages/runtime/tests/coverage/coverage-final.json new file mode 100644 index 000000000..75403130f --- /dev/null +++ b/packages/runtime/tests/coverage/coverage-final.json @@ -0,0 +1,2 @@ +{"/Users/yiming/git/zenstack/zenstack/packages/runtime/src/handler/data/query-processor.ts": {"path":"/Users/yiming/git/zenstack/zenstack/packages/runtime/src/handler/data/query-processor.ts","all":false,"statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":32}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":73}},"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":0}},"3":{"start":{"line":4,"column":0},"end":{"line":4,"column":29}},"4":{"start":{"line":5,"column":0},"end":{"line":5,"column":53}},"5":{"start":{"line":6,"column":0},"end":{"line":6,"column":0}},"6":{"start":{"line":7,"column":0},"end":{"line":7,"column":27}},"7":{"start":{"line":8,"column":0},"end":{"line":8,"column":22}},"8":{"start":{"line":9,"column":0},"end":{"line":9,"column":18}},"9":{"start":{"line":10,"column":0},"end":{"line":10,"column":39}},"10":{"start":{"line":11,"column":0},"end":{"line":11,"column":29}},"11":{"start":{"line":12,"column":0},"end":{"line":12,"column":7}},"12":{"start":{"line":13,"column":0},"end":{"line":13,"column":45}},"13":{"start":{"line":14,"column":0},"end":{"line":14,"column":78}},"14":{"start":{"line":15,"column":0},"end":{"line":15,"column":20}},"15":{"start":{"line":16,"column":0},"end":{"line":16,"column":27}},"16":{"start":{"line":17,"column":0},"end":{"line":17,"column":32}},"17":{"start":{"line":18,"column":0},"end":{"line":18,"column":20}},"18":{"start":{"line":19,"column":0},"end":{"line":19,"column":27}},"19":{"start":{"line":20,"column":0},"end":{"line":20,"column":42}},"20":{"start":{"line":21,"column":0},"end":{"line":21,"column":18}},"21":{"start":{"line":22,"column":0},"end":{"line":22,"column":13}},"22":{"start":{"line":23,"column":0},"end":{"line":23,"column":9}},"23":{"start":{"line":24,"column":0},"end":{"line":24,"column":0}},"24":{"start":{"line":25,"column":0},"end":{"line":25,"column":36}},"25":{"start":{"line":26,"column":0},"end":{"line":26,"column":60}},"26":{"start":{"line":27,"column":0},"end":{"line":27,"column":62}},"27":{"start":{"line":28,"column":0},"end":{"line":28,"column":71}},"28":{"start":{"line":29,"column":0},"end":{"line":29,"column":80}},"29":{"start":{"line":30,"column":0},"end":{"line":30,"column":53}},"30":{"start":{"line":31,"column":0},"end":{"line":31,"column":91}},"31":{"start":{"line":32,"column":0},"end":{"line":32,"column":96}},"32":{"start":{"line":33,"column":0},"end":{"line":33,"column":67}},"33":{"start":{"line":34,"column":0},"end":{"line":34,"column":39}},"34":{"start":{"line":35,"column":0},"end":{"line":35,"column":52}},"35":{"start":{"line":36,"column":0},"end":{"line":36,"column":34}},"36":{"start":{"line":37,"column":0},"end":{"line":37,"column":31}},"37":{"start":{"line":38,"column":0},"end":{"line":38,"column":22}},"38":{"start":{"line":39,"column":0},"end":{"line":39,"column":52}},"39":{"start":{"line":40,"column":0},"end":{"line":40,"column":17}},"40":{"start":{"line":41,"column":0},"end":{"line":41,"column":13}},"41":{"start":{"line":42,"column":0},"end":{"line":42,"column":9}},"42":{"start":{"line":43,"column":0},"end":{"line":43,"column":0}},"43":{"start":{"line":44,"column":0},"end":{"line":44,"column":17}},"44":{"start":{"line":45,"column":0},"end":{"line":45,"column":5}},"45":{"start":{"line":46,"column":0},"end":{"line":46,"column":0}},"46":{"start":{"line":47,"column":0},"end":{"line":47,"column":22}},"47":{"start":{"line":48,"column":0},"end":{"line":48,"column":22}},"48":{"start":{"line":49,"column":0},"end":{"line":49,"column":23}},"49":{"start":{"line":50,"column":0},"end":{"line":50,"column":18}},"50":{"start":{"line":51,"column":0},"end":{"line":51,"column":39}},"51":{"start":{"line":52,"column":0},"end":{"line":52,"column":29}},"52":{"start":{"line":53,"column":0},"end":{"line":53,"column":8}},"53":{"start":{"line":54,"column":0},"end":{"line":54,"column":1}}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":12,"8":12,"9":12,"10":12,"11":12,"12":12,"13":12,"14":12,"15":12,"16":9,"17":12,"18":3,"19":3,"20":3,"21":3,"22":12,"23":12,"24":12,"25":6,"26":6,"27":6,"28":8,"29":8,"30":4,"31":4,"32":4,"33":4,"34":4,"35":4,"36":4,"37":4,"38":4,"39":4,"40":8,"41":6,"42":12,"43":12,"44":12,"45":1,"46":1,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":1},"branchMap":{"0":{"type":"branch","line":5,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":53}},"locations":[{"start":{"line":5,"column":4},"end":{"line":5,"column":53}}]},"1":{"type":"branch","line":7,"loc":{"start":{"line":7,"column":10},"end":{"line":45,"column":5}},"locations":[{"start":{"line":7,"column":10},"end":{"line":45,"column":5}}]},"2":{"type":"branch","line":13,"loc":{"start":{"line":13,"column":40},"end":{"line":13,"column":44}},"locations":[{"start":{"line":13,"column":40},"end":{"line":13,"column":44}}]},"3":{"type":"branch","line":16,"loc":{"start":{"line":16,"column":26},"end":{"line":18,"column":19}},"locations":[{"start":{"line":16,"column":26},"end":{"line":18,"column":19}}]},"4":{"type":"branch","line":18,"loc":{"start":{"line":18,"column":13},"end":{"line":22,"column":13}},"locations":[{"start":{"line":18,"column":13},"end":{"line":22,"column":13}}]},"5":{"type":"branch","line":25,"loc":{"start":{"line":25,"column":21},"end":{"line":25,"column":33}},"locations":[{"start":{"line":25,"column":21},"end":{"line":25,"column":33}}]},"6":{"type":"branch","line":25,"loc":{"start":{"line":25,"column":35},"end":{"line":42,"column":9}},"locations":[{"start":{"line":25,"column":35},"end":{"line":42,"column":9}}]},"7":{"type":"branch","line":27,"loc":{"start":{"line":27,"column":39},"end":{"line":27,"column":50}},"locations":[{"start":{"line":27,"column":39},"end":{"line":27,"column":50}}]},"8":{"type":"branch","line":27,"loc":{"start":{"line":27,"column":51},"end":{"line":27,"column":61}},"locations":[{"start":{"line":27,"column":51},"end":{"line":27,"column":61}}]},"9":{"type":"branch","line":28,"loc":{"start":{"line":28,"column":70},"end":{"line":41,"column":13}},"locations":[{"start":{"line":28,"column":70},"end":{"line":41,"column":13}}]},"10":{"type":"branch","line":30,"loc":{"start":{"line":30,"column":29},"end":{"line":30,"column":50}},"locations":[{"start":{"line":30,"column":29},"end":{"line":30,"column":50}}]},"11":{"type":"branch","line":30,"loc":{"start":{"line":30,"column":52},"end":{"line":40,"column":17}},"locations":[{"start":{"line":30,"column":52},"end":{"line":40,"column":17}}]},"12":{"type":"branch","line":35,"loc":{"start":{"line":35,"column":39},"end":{"line":35,"column":43}},"locations":[{"start":{"line":35,"column":39},"end":{"line":35,"column":43}}]},"13":{"type":"branch","line":35,"loc":{"start":{"line":35,"column":44},"end":{"line":35,"column":51}},"locations":[{"start":{"line":35,"column":44},"end":{"line":35,"column":51}}]}},"b":{"0":[1],"1":[12],"2":[0],"3":[9],"4":[3],"5":[9],"6":[6],"7":[3],"8":[3],"9":[8],"10":[6],"11":[4],"12":[2],"13":[2]},"fnMap":{"0":{"name":"QueryProcessor","decl":{"start":{"line":5,"column":4},"end":{"line":5,"column":53}},"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":53}},"line":5},"1":{"name":"processQueryArgs","decl":{"start":{"line":7,"column":10},"end":{"line":45,"column":5}},"loc":{"start":{"line":7,"column":10},"end":{"line":45,"column":5}},"line":7},"2":{"name":"postProcess","decl":{"start":{"line":47,"column":10},"end":{"line":53,"column":8}},"loc":{"start":{"line":47,"column":10},"end":{"line":53,"column":8}},"line":47}},"f":{"0":1,"1":12,"2":0}} +} diff --git a/packages/runtime/tests/coverage/lcov-report/base.css b/packages/runtime/tests/coverage/lcov-report/base.css new file mode 100644 index 000000000..f418035b4 --- /dev/null +++ b/packages/runtime/tests/coverage/lcov-report/base.css @@ -0,0 +1,224 @@ +body, html { + margin:0; padding: 0; + height: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial; + font-size: 14px; + color:#333; +} +.small { font-size: 12px; } +*, *:after, *:before { + -webkit-box-sizing:border-box; + -moz-box-sizing:border-box; + box-sizing:border-box; + } +h1 { font-size: 20px; margin: 0;} +h2 { font-size: 14px; } +pre { + font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; + margin: 0; + padding: 0; + -moz-tab-size: 2; + -o-tab-size: 2; + tab-size: 2; +} +a { color:#0074D9; text-decoration:none; } +a:hover { text-decoration:underline; } +.strong { font-weight: bold; } +.space-top1 { padding: 10px 0 0 0; } +.pad2y { padding: 20px 0; } +.pad1y { padding: 10px 0; } +.pad2x { padding: 0 20px; } +.pad2 { padding: 20px; } +.pad1 { padding: 10px; } +.space-left2 { padding-left:55px; } +.space-right2 { padding-right:20px; } +.center { text-align:center; } +.clearfix { display:block; } +.clearfix:after { + content:''; + display:block; + height:0; + clear:both; + visibility:hidden; + } +.fl { float: left; } +@media only screen and (max-width:640px) { + .col3 { width:100%; max-width:100%; } + .hide-mobile { display:none!important; } +} + +.quiet { + color: #7f7f7f; + color: rgba(0,0,0,0.5); +} +.quiet a { opacity: 0.7; } + +.fraction { + font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; + font-size: 10px; + color: #555; + background: #E8E8E8; + padding: 4px 5px; + border-radius: 3px; + vertical-align: middle; +} + +div.path a:link, div.path a:visited { color: #333; } +table.coverage { + border-collapse: collapse; + margin: 10px 0 0 0; + padding: 0; +} + +table.coverage td { + margin: 0; + padding: 0; + vertical-align: top; +} +table.coverage td.line-count { + text-align: right; + padding: 0 5px 0 20px; +} +table.coverage td.line-coverage { + text-align: right; + padding-right: 10px; + min-width:20px; +} + +table.coverage td span.cline-any { + display: inline-block; + padding: 0 5px; + width: 100%; +} +.missing-if-branch { + display: inline-block; + margin-right: 5px; + border-radius: 3px; + position: relative; + padding: 0 4px; + background: #333; + color: yellow; +} + +.skip-if-branch { + display: none; + margin-right: 10px; + position: relative; + padding: 0 4px; + background: #ccc; + color: white; +} +.missing-if-branch .typ, .skip-if-branch .typ { + color: inherit !important; +} +.coverage-summary { + border-collapse: collapse; + width: 100%; +} +.coverage-summary tr { border-bottom: 1px solid #bbb; } +.keyline-all { border: 1px solid #ddd; } +.coverage-summary td, .coverage-summary th { padding: 10px; } +.coverage-summary tbody { border: 1px solid #bbb; } +.coverage-summary td { border-right: 1px solid #bbb; } +.coverage-summary td:last-child { border-right: none; } +.coverage-summary th { + text-align: left; + font-weight: normal; + white-space: nowrap; +} +.coverage-summary th.file { border-right: none !important; } +.coverage-summary th.pct { } +.coverage-summary th.pic, +.coverage-summary th.abs, +.coverage-summary td.pct, +.coverage-summary td.abs { text-align: right; } +.coverage-summary td.file { white-space: nowrap; } +.coverage-summary td.pic { min-width: 120px !important; } +.coverage-summary tfoot td { } + +.coverage-summary .sorter { + height: 10px; + width: 7px; + display: inline-block; + margin-left: 0.5em; + background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; +} +.coverage-summary .sorted .sorter { + background-position: 0 -20px; +} +.coverage-summary .sorted-desc .sorter { + background-position: 0 -10px; +} +.status-line { height: 10px; } +/* yellow */ +.cbranch-no { background: yellow !important; color: #111; } +/* dark red */ +.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } +.low .chart { border:1px solid #C21F39 } +.highlighted, +.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ + background: #C21F39 !important; +} +/* medium red */ +.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } +/* light red */ +.low, .cline-no { background:#FCE1E5 } +/* light green */ +.high, .cline-yes { background:rgb(230,245,208) } +/* medium green */ +.cstat-yes { background:rgb(161,215,106) } +/* dark green */ +.status-line.high, .high .cover-fill { background:rgb(77,146,33) } +.high .chart { border:1px solid rgb(77,146,33) } +/* dark yellow (gold) */ +.status-line.medium, .medium .cover-fill { background: #f9cd0b; } +.medium .chart { border:1px solid #f9cd0b; } +/* light yellow */ +.medium { background: #fff4c2; } + +.cstat-skip { background: #ddd; color: #111; } +.fstat-skip { background: #ddd; color: #111 !important; } +.cbranch-skip { background: #ddd !important; color: #111; } + +span.cline-neutral { background: #eaeaea; } + +.coverage-summary td.empty { + opacity: .5; + padding-top: 4px; + padding-bottom: 4px; + line-height: 1; + color: #888; +} + +.cover-fill, .cover-empty { + display:inline-block; + height: 12px; +} +.chart { + line-height: 0; +} +.cover-empty { + background: white; +} +.cover-full { + border-right: none !important; +} +pre.prettyprint { + border: none !important; + padding: 0 !important; + margin: 0 !important; +} +.com { color: #999 !important; } +.ignore-none { color: #999; font-weight: normal; } + +.wrapper { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -48px; +} +.footer, .push { + height: 48px; +} diff --git a/packages/runtime/tests/coverage/lcov-report/block-navigation.js b/packages/runtime/tests/coverage/lcov-report/block-navigation.js new file mode 100644 index 000000000..cc1213023 --- /dev/null +++ b/packages/runtime/tests/coverage/lcov-report/block-navigation.js @@ -0,0 +1,87 @@ +/* eslint-disable */ +var jumpToCode = (function init() { + // Classes of code we would like to highlight in the file view + var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; + + // Elements to highlight in the file listing view + var fileListingElements = ['td.pct.low']; + + // We don't want to select elements that are direct descendants of another match + var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` + + // Selecter that finds elements on the page to which we can jump + var selector = + fileListingElements.join(', ') + + ', ' + + notSelector + + missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` + + // The NodeList of matching elements + var missingCoverageElements = document.querySelectorAll(selector); + + var currentIndex; + + function toggleClass(index) { + missingCoverageElements + .item(currentIndex) + .classList.remove('highlighted'); + missingCoverageElements.item(index).classList.add('highlighted'); + } + + function makeCurrent(index) { + toggleClass(index); + currentIndex = index; + missingCoverageElements.item(index).scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'center' + }); + } + + function goToPrevious() { + var nextIndex = 0; + if (typeof currentIndex !== 'number' || currentIndex === 0) { + nextIndex = missingCoverageElements.length - 1; + } else if (missingCoverageElements.length > 1) { + nextIndex = currentIndex - 1; + } + + makeCurrent(nextIndex); + } + + function goToNext() { + var nextIndex = 0; + + if ( + typeof currentIndex === 'number' && + currentIndex < missingCoverageElements.length - 1 + ) { + nextIndex = currentIndex + 1; + } + + makeCurrent(nextIndex); + } + + return function jump(event) { + if ( + document.getElementById('fileSearch') === document.activeElement && + document.activeElement != null + ) { + // if we're currently focused on the search input, we don't want to navigate + return; + } + + switch (event.which) { + case 78: // n + case 74: // j + goToNext(); + break; + case 66: // b + case 75: // k + case 80: // p + goToPrevious(); + break; + } + }; +})(); +window.addEventListener('keydown', jumpToCode); diff --git a/packages/runtime/tests/coverage/lcov-report/favicon.png b/packages/runtime/tests/coverage/lcov-report/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..c1525b811a167671e9de1fa78aab9f5c0b61cef7 GIT binary patch literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> + + + + Code coverage report for All files + + + + + + + + + +
    +
    +

    All files

    +
    + +
    + 88.88% + Statements + 48/54 +
    + + +
    + 92.85% + Branches + 13/14 +
    + + +
    + 66.66% + Functions + 2/3 +
    + + +
    + 88.88% + Lines + 48/54 +
    + + +
    +

    + Press n or j to go to the next uncovered block, b, p or k for the previous block. +

    + +
    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    FileStatementsBranchesFunctionsLines
    query-processor.ts +
    +
    88.88%48/5492.85%13/1466.66%2/388.88%48/54
    +
    +
    +
    + + + + + + + + \ No newline at end of file diff --git a/packages/runtime/tests/coverage/lcov-report/prettify.css b/packages/runtime/tests/coverage/lcov-report/prettify.css new file mode 100644 index 000000000..b317a7cda --- /dev/null +++ b/packages/runtime/tests/coverage/lcov-report/prettify.css @@ -0,0 +1 @@ +.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/packages/runtime/tests/coverage/lcov-report/prettify.js b/packages/runtime/tests/coverage/lcov-report/prettify.js new file mode 100644 index 000000000..b3225238f --- /dev/null +++ b/packages/runtime/tests/coverage/lcov-report/prettify.js @@ -0,0 +1,2 @@ +/* eslint-disable */ +window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/packages/runtime/tests/coverage/lcov-report/query-processor.ts.html b/packages/runtime/tests/coverage/lcov-report/query-processor.ts.html new file mode 100644 index 000000000..c50ed09a5 --- /dev/null +++ b/packages/runtime/tests/coverage/lcov-report/query-processor.ts.html @@ -0,0 +1,247 @@ + + + + + + Code coverage report for query-processor.ts + + + + + + + + + +
    +
    +

    All files query-processor.ts

    +
    + +
    + 88.88% + Statements + 48/54 +
    + + +
    + 92.85% + Branches + 13/14 +
    + + +
    + 66.66% + Functions + 2/3 +
    + + +
    + 88.88% + Lines + 48/54 +
    + + +
    +

    + Press n or j to go to the next uncovered block, b, p or k for the previous block. +

    + +
    +
    +
    
    +
    1 +2 +3 +4 +5 +6 +7 +8 +9 +10 +11 +12 +13 +14 +15 +16 +17 +18 +19 +20 +21 +22 +23 +24 +25 +26 +27 +28 +29 +30 +31 +32 +33 +34 +35 +36 +37 +38 +39 +40 +41 +42 +43 +44 +45 +46 +47 +48 +49 +50 +51 +52 +53 +54 +551x +1x +1x +1x +1x +1x +1x +12x +12x +12x +12x +12x +12x +12x +12x +12x +9x +12x +3x +3x +3x +3x +12x +12x +12x +6x +6x +6x +8x +8x +4x +4x +4x +4x +4x +4x +4x +4x +4x +4x +8x +6x +12x +12x +12x +1x +1x +  +  +  +  +  +  +1x + 
    import deepcopy from 'deepcopy';
    +import { PolicyOperationKind, QueryContext, Service } from '../../types';
    + 
    +export class QueryProcessor {
    +    constructor(private readonly service: Service) {}
    + 
    +    async processQueryArgs(
    +        model: string,
    +        args: any,
    +        operation: PolicyOperationKind,
    +        context: QueryContext
    +    ) {
    +        const r = args ? deepcopy(args) : {};
    +        const guard = this.service.buildQueryGuard(model, operation, context);
    +        if (guard) {
    +            if (!r.where) {
    +                r.where = guard;
    +            } else {
    +                r.where = {
    +                    AND: [guard, r.where],
    +                };
    +            }
    +        }
    + 
    +        if (r.include || r.select) {
    +            // "include" and "select" are mutually exclusive
    +            const selector = r.include ? 'include' : 'select';
    +            for (const [field, value] of Object.entries(r[selector])) {
    +                const fieldInfo = await this.service.resolveField(model, field);
    +                if (fieldInfo && fieldInfo.isArray) {
    +                    // note that Prisma only allows to attach filter for "to-many" relation
    +                    // query, so we need to handle "to-one" filter separately in post-processing
    +                    const fieldGuard = await this.processQueryArgs(
    +                        fieldInfo.type,
    +                        value === true ? {} : value,
    +                        operation,
    +                        context
    +                    );
    +                    r[selector][field] = fieldGuard;
    +                }
    +            }
    +        }
    + 
    +        return r;
    +    }
    + 
    +    async postProcess(
    +        model: string,
    +        queryArgs: any,
    +        data: any,
    +        operation: PolicyOperationKind,
    +        context: QueryContext
    +    ) {}
    +}
    + 
    + +
    +
    + + + + + + + + \ No newline at end of file diff --git a/packages/runtime/tests/coverage/lcov-report/sort-arrow-sprite.png b/packages/runtime/tests/coverage/lcov-report/sort-arrow-sprite.png new file mode 100644 index 0000000000000000000000000000000000000000..6ed68316eb3f65dec9063332d2f69bf3093bbfab GIT binary patch literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc literal 0 HcmV?d00001 diff --git a/packages/runtime/tests/coverage/lcov-report/sorter.js b/packages/runtime/tests/coverage/lcov-report/sorter.js new file mode 100644 index 000000000..2bb296a8c --- /dev/null +++ b/packages/runtime/tests/coverage/lcov-report/sorter.js @@ -0,0 +1,196 @@ +/* eslint-disable */ +var addSorting = (function() { + 'use strict'; + var cols, + currentSort = { + index: 0, + desc: false + }; + + // returns the summary table element + function getTable() { + return document.querySelector('.coverage-summary'); + } + // returns the thead element of the summary table + function getTableHeader() { + return getTable().querySelector('thead tr'); + } + // returns the tbody element of the summary table + function getTableBody() { + return getTable().querySelector('tbody'); + } + // returns the th element for nth column + function getNthColumn(n) { + return getTableHeader().querySelectorAll('th')[n]; + } + + function onFilterInput() { + const searchValue = document.getElementById('fileSearch').value; + const rows = document.getElementsByTagName('tbody')[0].children; + for (let i = 0; i < rows.length; i++) { + const row = rows[i]; + if ( + row.textContent + .toLowerCase() + .includes(searchValue.toLowerCase()) + ) { + row.style.display = ''; + } else { + row.style.display = 'none'; + } + } + } + + // loads the search box + function addSearchBox() { + var template = document.getElementById('filterTemplate'); + var templateClone = template.content.cloneNode(true); + templateClone.getElementById('fileSearch').oninput = onFilterInput; + template.parentElement.appendChild(templateClone); + } + + // loads all columns + function loadColumns() { + var colNodes = getTableHeader().querySelectorAll('th'), + colNode, + cols = [], + col, + i; + + for (i = 0; i < colNodes.length; i += 1) { + colNode = colNodes[i]; + col = { + key: colNode.getAttribute('data-col'), + sortable: !colNode.getAttribute('data-nosort'), + type: colNode.getAttribute('data-type') || 'string' + }; + cols.push(col); + if (col.sortable) { + col.defaultDescSort = col.type === 'number'; + colNode.innerHTML = + colNode.innerHTML + ''; + } + } + return cols; + } + // attaches a data attribute to every tr element with an object + // of data values keyed by column name + function loadRowData(tableRow) { + var tableCols = tableRow.querySelectorAll('td'), + colNode, + col, + data = {}, + i, + val; + for (i = 0; i < tableCols.length; i += 1) { + colNode = tableCols[i]; + col = cols[i]; + val = colNode.getAttribute('data-value'); + if (col.type === 'number') { + val = Number(val); + } + data[col.key] = val; + } + return data; + } + // loads all row data + function loadData() { + var rows = getTableBody().querySelectorAll('tr'), + i; + + for (i = 0; i < rows.length; i += 1) { + rows[i].data = loadRowData(rows[i]); + } + } + // sorts the table using the data for the ith column + function sortByIndex(index, desc) { + var key = cols[index].key, + sorter = function(a, b) { + a = a.data[key]; + b = b.data[key]; + return a < b ? -1 : a > b ? 1 : 0; + }, + finalSorter = sorter, + tableBody = document.querySelector('.coverage-summary tbody'), + rowNodes = tableBody.querySelectorAll('tr'), + rows = [], + i; + + if (desc) { + finalSorter = function(a, b) { + return -1 * sorter(a, b); + }; + } + + for (i = 0; i < rowNodes.length; i += 1) { + rows.push(rowNodes[i]); + tableBody.removeChild(rowNodes[i]); + } + + rows.sort(finalSorter); + + for (i = 0; i < rows.length; i += 1) { + tableBody.appendChild(rows[i]); + } + } + // removes sort indicators for current column being sorted + function removeSortIndicators() { + var col = getNthColumn(currentSort.index), + cls = col.className; + + cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); + col.className = cls; + } + // adds sort indicators for current column being sorted + function addSortIndicators() { + getNthColumn(currentSort.index).className += currentSort.desc + ? ' sorted-desc' + : ' sorted'; + } + // adds event listeners for all sorter widgets + function enableUI() { + var i, + el, + ithSorter = function ithSorter(i) { + var col = cols[i]; + + return function() { + var desc = col.defaultDescSort; + + if (currentSort.index === i) { + desc = !currentSort.desc; + } + sortByIndex(i, desc); + removeSortIndicators(); + currentSort.index = i; + currentSort.desc = desc; + addSortIndicators(); + }; + }; + for (i = 0; i < cols.length; i += 1) { + if (cols[i].sortable) { + // add the click event handler on the th so users + // dont have to click on those tiny arrows + el = getNthColumn(i).querySelector('.sorter').parentElement; + if (el.addEventListener) { + el.addEventListener('click', ithSorter(i)); + } else { + el.attachEvent('onclick', ithSorter(i)); + } + } + } + } + // adds sorting functionality to the UI + return function() { + if (!getTable()) { + return; + } + cols = loadColumns(); + loadData(); + addSearchBox(); + addSortIndicators(); + enableUI(); + }; +})(); + +window.addEventListener('load', addSorting); diff --git a/packages/runtime/tests/coverage/lcov.info b/packages/runtime/tests/coverage/lcov.info new file mode 100644 index 000000000..4eb00d717 --- /dev/null +++ b/packages/runtime/tests/coverage/lcov.info @@ -0,0 +1,83 @@ +TN: +SF:src/handler/data/query-processor.ts +FN:5,QueryProcessor +FN:7,processQueryArgs +FN:47,postProcess +FNF:3 +FNH:2 +FNDA:1,QueryProcessor +FNDA:12,processQueryArgs +FNDA:0,postProcess +DA:1,1 +DA:2,1 +DA:3,1 +DA:4,1 +DA:5,1 +DA:6,1 +DA:7,1 +DA:8,12 +DA:9,12 +DA:10,12 +DA:11,12 +DA:12,12 +DA:13,12 +DA:14,12 +DA:15,12 +DA:16,12 +DA:17,9 +DA:18,12 +DA:19,3 +DA:20,3 +DA:21,3 +DA:22,3 +DA:23,12 +DA:24,12 +DA:25,12 +DA:26,6 +DA:27,6 +DA:28,6 +DA:29,8 +DA:30,8 +DA:31,4 +DA:32,4 +DA:33,4 +DA:34,4 +DA:35,4 +DA:36,4 +DA:37,4 +DA:38,4 +DA:39,4 +DA:40,4 +DA:41,8 +DA:42,6 +DA:43,12 +DA:44,12 +DA:45,12 +DA:46,1 +DA:47,1 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:53,0 +DA:54,1 +LF:54 +LH:48 +BRDA:5,0,0,1 +BRDA:7,1,0,12 +BRDA:13,2,0,0 +BRDA:16,3,0,9 +BRDA:18,4,0,3 +BRDA:25,5,0,9 +BRDA:25,6,0,6 +BRDA:27,7,0,3 +BRDA:27,8,0,3 +BRDA:28,9,0,8 +BRDA:30,10,0,6 +BRDA:30,11,0,4 +BRDA:35,12,0,2 +BRDA:35,13,0,2 +BRF:14 +BRH:13 +end_of_record diff --git a/packages/runtime/tests/query-processor.test.ts b/packages/runtime/tests/query-processor.test.ts new file mode 100644 index 000000000..1bdc61709 --- /dev/null +++ b/packages/runtime/tests/query-processor.test.ts @@ -0,0 +1,170 @@ +import { + FieldInfo, + PolicyOperationKind, + QueryContext, + type Service, +} from '../src/types'; +import { QueryProcessor } from '../src/handler/data/query-processor'; + +class MockService implements Service { + constructor( + private readonly fieldMapping: Record> + ) {} + + get db(): any { + throw new Error('Method not implemented.'); + } + + async resolveField(model: string, field: string) { + return this.fieldMapping[model]?.[field]; + } + + buildQueryGuard( + model: string, + operation: PolicyOperationKind, + context: QueryContext + ) { + return { [`${model}_${operation}`]: true }; + } +} + +describe('Query Processor Tests', () => { + it('arg processor', async () => { + const svc = new MockService({ + List: { + todos: { + type: 'Todo', + isArray: true, + }, + }, + Todo: { + list: { + type: 'List', + isArray: false, + }, + }, + }); + + const processor = new QueryProcessor(svc); + + // empty args + let r = await processor.processQueryArgs('List', {}, 'read', {}); + expect(r).toEqual( + expect.objectContaining({ where: { List_read: true } }) + ); + + // simple condition + r = await processor.processQueryArgs( + 'List', + { where: { private: false } }, + 'read', + {} + ); + expect(r).toEqual( + expect.objectContaining({ + where: { + AND: expect.arrayContaining([ + { private: false }, + { List_read: true }, + ]), + }, + }) + ); + + // include to-many + r = await processor.processQueryArgs( + 'List', + { include: { todos: true } }, + 'read', + {} + ); + expect(r).toEqual( + expect.objectContaining({ + include: { todos: { where: { Todo_read: true } } }, + }) + ); + + // include to-many with condition + r = await processor.processQueryArgs( + 'List', + { include: { haha: true, todos: { where: { private: false } } } }, + 'read', + {} + ); + expect(r).toEqual( + expect.objectContaining({ + include: { + haha: true, + todos: { + where: { + AND: expect.arrayContaining([ + { private: false }, + { Todo_read: true }, + ]), + }, + }, + }, + }) + ); + + // select to-many + r = await processor.processQueryArgs( + 'List', + { select: { haha: true, todos: true } }, + 'read', + {} + ); + expect(r).toEqual( + expect.objectContaining({ + select: { + haha: true, + todos: { + where: { + Todo_read: true, + }, + }, + }, + }) + ); + + // select to-many with condition + r = await processor.processQueryArgs( + 'List', + { select: { todos: { where: { private: false } } } }, + 'read', + {} + ); + expect(r).toEqual( + expect.objectContaining({ + select: { + todos: { + where: { + AND: expect.arrayContaining([ + { private: false }, + { Todo_read: true }, + ]), + }, + }, + }, + }) + ); + + // include to-one, no processing + r = await processor.processQueryArgs( + 'Todo', + { include: { list: true } }, + 'read', + {} + ); + expect(r).toEqual(expect.objectContaining({ include: { list: true } })); + + // select to-one, no processing + r = await processor.processQueryArgs( + 'Todo', + { select: { list: true } }, + 'read', + {} + ); + expect(r).toEqual(expect.objectContaining({ select: { list: true } })); + }); +}); diff --git a/packages/runtime/tsconfig.json b/packages/runtime/tsconfig.json index 0cb440399..a678f9c39 100644 --- a/packages/runtime/tsconfig.json +++ b/packages/runtime/tsconfig.json @@ -4,7 +4,7 @@ "module": "ESNext", "lib": ["ESNext", "DOM"], "sourceMap": true, - "outDir": "./lib", + "outDir": "lib", "strict": true, "noUnusedLocals": true, "noImplicitReturns": true, @@ -12,7 +12,9 @@ "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, - "declaration": true + "declaration": true, + "resolveJsonModule": true, + "paths": {} }, "include": ["src/**/*.ts"], "exclude": ["lib", "node_modules"] diff --git a/packages/schema/.gitignore b/packages/schema/.gitignore index 6a3417b8d..311a0bbcb 100644 --- a/packages/schema/.gitignore +++ b/packages/schema/.gitignore @@ -1 +1,2 @@ /out/ +/tests/coverage/ diff --git a/packages/schema/jest.config.ts b/packages/schema/jest.config.ts index 9f686b1cc..5fde9b5bf 100644 --- a/packages/schema/jest.config.ts +++ b/packages/schema/jest.config.ts @@ -11,37 +11,19 @@ export default { clearMocks: true, // Indicates whether the coverage information should be collected while executing the test - // collectCoverage: false, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: undefined, + collectCoverage: true, // The directory where Jest should output its coverage files - // coverageDirectory: undefined, + coverageDirectory: 'tests/coverage', // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "/node_modules/" - // ], + coveragePathIgnorePatterns: ['/node_modules/', '/tests/'], // Indicates which provider should be used to instrument code for coverage coverageProvider: 'v8', // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // The root directory that Jest should scan for tests and modules within - // rootDir: undefined, - - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], + coverageReporters: ['json', 'text', 'lcov', 'clover'], // A map from regular expressions to paths to transformers transform: { '^.+\\.tsx?$': 'ts-jest' }, diff --git a/packages/schema/src/generator/constants.ts b/packages/schema/src/generator/constants.ts index 3d59f2708..fb202ca08 100644 --- a/packages/schema/src/generator/constants.ts +++ b/packages/schema/src/generator/constants.ts @@ -1 +1,2 @@ export const RUNTIME_PACKAGE = '@zenstackhq/runtime'; +export const GUARD_FIELD_NAME = 'zenstack_guard'; diff --git a/packages/schema/src/generator/prisma/index.ts b/packages/schema/src/generator/prisma/index.ts index 3ca2a0057..09f7eaab6 100644 --- a/packages/schema/src/generator/prisma/index.ts +++ b/packages/schema/src/generator/prisma/index.ts @@ -13,6 +13,7 @@ import { Expression, InvocationExpr, isArrayExpr, + isDataModel, isEnum, isInvocationExpr, isLiteralExpr, @@ -36,11 +37,9 @@ import { } from './prisma-builder'; import { execSync } from 'child_process'; import { Project, SourceFile, VariableDeclarationKind } from 'ts-morph'; -import { RUNTIME_PACKAGE } from '../constants'; +import { GUARD_FIELD_NAME, RUNTIME_PACKAGE } from '../constants'; import type { PolicyKind, PolicyOperationKind } from '@zenstackhq/runtime'; import ExpressionWriter from '../server/data/expression-writer'; -import { extractDataModelsWithAllowRules } from '../utils'; -import { camelCase } from 'change-case'; const supportedProviders = ['postgresql', 'mysql', 'sqlite', 'sqlserver']; const supportedAttrbutes = [ @@ -214,7 +213,7 @@ export default class PrismaGenerator implements Generator { } // add an "zenstack_guard" field for dealing with pure auth() related conditions - model.addField('zenstack_guard', 'Boolean', [ + model.addField(GUARD_FIELD_NAME, 'Boolean', [ new PrismaFieldAttribute('default', [ new PrismaAttributeArg( undefined, @@ -359,15 +358,49 @@ export default class PrismaGenerator implements Generator { }); } - const models = extractDataModelsWithAllowRules(context.schema); - models.forEach((model) => - this.generateQueryGuardForModel(model as DataModel, sf) - ); + // const models = extractDataModelsWithAllowRules(context.schema); + const models = context.schema.declarations.filter((d) => + isDataModel(d) + ) as DataModel[]; + + this.generateFieldMapping(models, sf); + + models.forEach((model) => this.generateQueryGuardForModel(model, sf)); sf.formatText({}); await project.save(); } + private generateFieldMapping(models: DataModel[], sourceFile: SourceFile) { + const mapping = Object.fromEntries( + models.map((m) => [ + m.name, + Object.fromEntries( + m.fields + .filter((f) => isDataModel(f.type.reference?.ref)) + .map((f) => [ + f.name, + { + type: f.type.reference!.ref!.name, + isArray: f.type.array, + }, + ]) + ), + ]) + ); + + sourceFile.addVariableStatement({ + isExported: true, + declarationKind: VariableDeclarationKind.Const, + declarations: [ + { + name: '_fieldMapping', + initializer: JSON.stringify(mapping), + }, + ], + }); + } + private getPolicyExpressions( model: DataModel, kind: PolicyKind, @@ -399,7 +432,7 @@ export default class PrismaGenerator implements Generator { for (const kind of ['create', 'update', 'read', 'delete']) { const func = sourceFile .addFunction({ - name: camelCase(model.name) + '_' + kind, + name: model.name + '_' + kind, returnType: 'any', parameters: [ { @@ -482,7 +515,8 @@ export default class PrismaGenerator implements Generator { } else if (allows.length > 0) { writeAllows(); } else { - writer.write('undefined'); + // disallow any operation + writer.write(`{ ${GUARD_FIELD_NAME}: false }`); } }, }, diff --git a/packages/schema/src/generator/react-hooks/index.ts b/packages/schema/src/generator/react-hooks/index.ts index da786a9bf..e361bdd7c 100644 --- a/packages/schema/src/generator/react-hooks/index.ts +++ b/packages/schema/src/generator/react-hooks/index.ts @@ -1,7 +1,7 @@ import { Context, Generator } from '../types'; import { Project } from 'ts-morph'; import * as path from 'path'; -import { camelCase, paramCase } from 'change-case'; +import { paramCase } from 'change-case'; import { DataModel } from '@lang/generated/ast'; import colors from 'colors'; import { extractDataModelsWithAllowRules } from '../utils'; @@ -129,9 +129,7 @@ export default class ReactHooksGenerator implements Generator { sf.addStatements([`import * as request from './request';`]); - sf.addStatements( - `const endpoint = '/api/zen/data/${camelCase(model.name)}';` - ); + sf.addStatements(`const endpoint = '/api/zen/data/${model.name}';`); const useFuncBody = sf .addFunction({ diff --git a/packages/schema/src/generator/service/index.ts b/packages/schema/src/generator/service/index.ts index e715e2cde..8155c311c 100644 --- a/packages/schema/src/generator/service/index.ts +++ b/packages/schema/src/generator/service/index.ts @@ -41,6 +41,26 @@ export default class ServiceGenerator implements Generator { .addBody() .setBodyText('return this._prisma;'); + cls + .addMethod({ + name: 'resolveField', + isAsync: true, + parameters: [ + { + name: 'model', + type: 'string', + }, + { + name: 'field', + type: 'string', + }, + ], + }) + .addBody().setBodyText(` + const module: any = await import('./query/guard'); + return module._fieldMapping?.[model]?.[field]; + `); + cls .addMethod({ name: 'buildQueryGuard', diff --git a/packages/schema/src/utils/indent-string.ts b/packages/schema/src/utils/indent-string.ts index 715b9be93..f9a52db1a 100644 --- a/packages/schema/src/utils/indent-string.ts +++ b/packages/schema/src/utils/indent-string.ts @@ -1,41 +1,6 @@ // https://github.com/sindresorhus/indent-string -export default function indentString( - string: string, - count = 4, - options: { indent?: string; includeEmptyLines?: boolean } = {} -) { - const { indent = ' ', includeEmptyLines = false } = options; - - if (typeof string !== 'string') { - throw new TypeError( - `Expected \`input\` to be a \`string\`, got \`${typeof string}\`` - ); - } - - if (typeof count !== 'number') { - throw new TypeError( - `Expected \`count\` to be a \`number\`, got \`${typeof count}\`` - ); - } - - if (count < 0) { - throw new RangeError( - `Expected \`count\` to be at least 0, got \`${count}\`` - ); - } - - if (typeof indent !== 'string') { - throw new TypeError( - `Expected \`options.indent\` to be a \`string\`, got \`${typeof indent}\`` - ); - } - - if (count === 0) { - return string; - } - - const regex = includeEmptyLines ? /^/gm : /^(?!\s*$)/gm; - - return string.replace(regex, indent.repeat(count)); +export default function indentString(string: string, count = 4) { + const indent = ' '; + return string.replace(/^/gm, indent.repeat(count)); } diff --git a/packages/schema/tests/generator/expression-writer.test.ts b/packages/schema/tests/generator/expression-writer.test.ts index dd1255a40..bd1a6ee31 100644 --- a/packages/schema/tests/generator/expression-writer.test.ts +++ b/packages/schema/tests/generator/expression-writer.test.ts @@ -8,6 +8,7 @@ import { } from '../../src/language-server/generated/ast'; import { loadModel } from '../utils'; import * as tmp from 'tmp'; +import { GUARD_FIELD_NAME } from '../../src/generator/constants'; import expressionWriter from '../../src/generator/server/data/expression-writer'; async function check( @@ -98,7 +99,7 @@ describe('Expression Writer Tests', () => { } `, (model) => model.attributes[0].args[1].value, - `{ zenstack_guard: true }` + `{ ${GUARD_FIELD_NAME}: true }` ); await check( @@ -108,7 +109,7 @@ describe('Expression Writer Tests', () => { } `, (model) => model.attributes[0].args[1].value, - `{ zenstack_guard: false }` + `{ ${GUARD_FIELD_NAME}: false }` ); }); @@ -583,7 +584,7 @@ describe('Expression Writer Tests', () => { } `, (model) => model.attributes[0].args[1].value, - `{ zenstack_guard: user == null }` + `{ ${GUARD_FIELD_NAME}: user == null }` ); await check( @@ -593,7 +594,7 @@ describe('Expression Writer Tests', () => { } `, (model) => model.attributes[0].args[1].value, - `{ zenstack_guard: user != null }` + `{ ${GUARD_FIELD_NAME}: user != null }` ); }); diff --git a/packages/schema/tests/generator/prisma-builder.test.ts b/packages/schema/tests/generator/prisma-builder.test.ts index a420ba9e0..06c530c3e 100644 --- a/packages/schema/tests/generator/prisma-builder.test.ts +++ b/packages/schema/tests/generator/prisma-builder.test.ts @@ -13,7 +13,6 @@ import { getDMMF } from '@prisma/internals'; async function validate(model: PrismaModel) { const content = model.toString(); - console.log(`Prisma content:\n${content}`); try { return await getDMMF({ datamodel: content }); } catch (err) { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a8704601f..9085e8b73 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -7,11 +7,18 @@ importers: packages/runtime: specifiers: + '@types/jest': ^29.0.3 + '@types/node': ^14.18.29 deepcopy: ^2.1.0 + jest: ^29.0.3 next: 12.3.1 react: ^17.0.2 || ^18 react-dom: ^17.0.2 || ^18 swr: ^1.3.0 + ts-jest: ^29.0.1 + ts-node: ^10.9.1 + tsc-alias: ^1.7.0 + tsconfig-paths-jest: ^0.0.1 typescript: ^4.6.2 dependencies: deepcopy: 2.1.0 @@ -20,6 +27,13 @@ importers: react-dom: 18.2.0_react@18.2.0 swr: 1.3.0_react@18.2.0 devDependencies: + '@types/jest': 29.0.3 + '@types/node': 14.18.29 + jest: 29.0.3_johvxhudwcpndp4mle25vwrlq4 + ts-jest: 29.0.1_poggjixajg6vd6yquly7s7dsj4 + ts-node: 10.9.1_ck2axrxkiif44rdbzjywaqjysa + tsc-alias: 1.7.0 + tsconfig-paths-jest: 0.0.1 typescript: 4.8.3 packages/schema: @@ -94,7 +108,7 @@ packages: engines: {node: '>=6.0.0'} dependencies: '@jridgewell/gen-mapping': 0.1.1 - '@jridgewell/trace-mapping': 0.3.15 + '@jridgewell/trace-mapping': 0.3.16 dev: true /@babel/code-frame/7.12.11: @@ -110,39 +124,11 @@ packages: '@babel/highlight': 7.18.6 dev: true - /@babel/compat-data/7.19.1: - resolution: {integrity: sha512-72a9ghR0gnESIa7jBN53U32FOVCEoztyIlKaNoU05zRhEecduGK9L9c3ww7Mp06JiR+0ls0GBPFJQwwtjn9ksg==} - engines: {node: '>=6.9.0'} - dev: true - /@babel/compat-data/7.19.4: resolution: {integrity: sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==} engines: {node: '>=6.9.0'} dev: true - /@babel/core/7.19.1: - resolution: {integrity: sha512-1H8VgqXme4UXCRv7/Wa1bq7RVymKOzC7znjyFM8KiEzwFqcKUKYNoQef4GhdklgNvoBXyW4gYhuBNCM5o1zImw==} - engines: {node: '>=6.9.0'} - dependencies: - '@ampproject/remapping': 2.2.0 - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.19.0 - '@babel/helper-compilation-targets': 7.19.1_@babel+core@7.19.1 - '@babel/helper-module-transforms': 7.19.0 - '@babel/helpers': 7.19.0 - '@babel/parser': 7.19.1 - '@babel/template': 7.18.10 - '@babel/traverse': 7.19.1 - '@babel/types': 7.19.0 - convert-source-map: 1.8.0 - debug: 4.3.4 - gensync: 1.0.0-beta.2 - json5: 2.2.1 - semver: 6.3.0 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/core/7.19.3: resolution: {integrity: sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==} engines: {node: '>=6.9.0'} @@ -166,15 +152,6 @@ packages: - supports-color dev: true - /@babel/generator/7.19.0: - resolution: {integrity: sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.19.0 - '@jridgewell/gen-mapping': 0.3.2 - jsesc: 2.5.2 - dev: true - /@babel/generator/7.19.5: resolution: {integrity: sha512-DxbNz9Lz4aMZ99qPpO1raTbcrI1ZeYh+9NR9qhfkQIbFtVEqotHojEBxHzmxhVONkGt6VyrqVQcgpefMy9pqcg==} engines: {node: '>=6.9.0'} @@ -184,19 +161,6 @@ packages: jsesc: 2.5.2 dev: true - /@babel/helper-compilation-targets/7.19.1_@babel+core@7.19.1: - resolution: {integrity: sha512-LlLkkqhCMyz2lkQPvJNdIYU7O5YjWRgC2R4omjCTpZd8u8KMQzZvX4qce+/BluN1rcQiV7BoGUpmQ0LeHerbhg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - dependencies: - '@babel/compat-data': 7.19.1 - '@babel/core': 7.19.1 - '@babel/helper-validator-option': 7.18.6 - browserslist: 4.21.4 - semver: 6.3.0 - dev: true - /@babel/helper-compilation-targets/7.19.3_@babel+core@7.19.3: resolution: {integrity: sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==} engines: {node: '>=6.9.0'} @@ -220,21 +184,21 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.18.10 - '@babel/types': 7.19.0 + '@babel/types': 7.19.4 dev: true /@babel/helper-hoist-variables/7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.19.0 + '@babel/types': 7.19.4 dev: true /@babel/helper-module-imports/7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.19.3 + '@babel/types': 7.19.4 dev: true /@babel/helper-module-transforms/7.19.0: @@ -247,8 +211,8 @@ packages: '@babel/helper-split-export-declaration': 7.18.6 '@babel/helper-validator-identifier': 7.19.1 '@babel/template': 7.18.10 - '@babel/traverse': 7.19.1 - '@babel/types': 7.19.0 + '@babel/traverse': 7.19.4 + '@babel/types': 7.19.4 transitivePeerDependencies: - supports-color dev: true @@ -262,19 +226,14 @@ packages: resolution: {integrity: sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.19.3 + '@babel/types': 7.19.4 dev: true /@babel/helper-split-export-declaration/7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.19.0 - dev: true - - /@babel/helper-string-parser/7.18.10: - resolution: {integrity: sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==} - engines: {node: '>=6.9.0'} + '@babel/types': 7.19.4 dev: true /@babel/helper-string-parser/7.19.4: @@ -292,17 +251,6 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helpers/7.19.0: - resolution: {integrity: sha512-DRBCKGwIEdqY3+rPJgG/dKfQy9+08rHIAJx8q2p+HSWP87s2HCrQmaAMMyMll2kIXKCW0cO1RdQskx15Xakftg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.18.10 - '@babel/traverse': 7.19.1 - '@babel/types': 7.19.0 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/helpers/7.19.4: resolution: {integrity: sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==} engines: {node: '>=6.9.0'} @@ -323,14 +271,6 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/parser/7.19.1: - resolution: {integrity: sha512-h7RCSorm1DdTVGJf3P2Mhj3kdnkmF/EiysUkzS2TdgAYqyjFdMQJbVuXOBej2SBJaXan/lIVtT6KkGbyyq753A==} - engines: {node: '>=6.0.0'} - hasBin: true - dependencies: - '@babel/types': 7.19.0 - dev: true - /@babel/parser/7.19.4: resolution: {integrity: sha512-qpVT7gtuOLjWeDTKLkJ6sryqLliBaFpAtGeqw5cs5giLldvh+Ch0plqnUMKoVAUS6ZEueQQiZV+p5pxtPitEsA==} engines: {node: '>=6.0.0'} @@ -339,132 +279,132 @@ packages: '@babel/types': 7.19.4 dev: true - /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.19.1: + /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.19.3: resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.19.1: + /@babel/plugin-syntax-bigint/7.8.3_@babel+core@7.19.3: resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.19.1: + /@babel/plugin-syntax-class-properties/7.12.13_@babel+core@7.19.3: resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.19.1: + /@babel/plugin-syntax-import-meta/7.10.4_@babel+core@7.19.3: resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.19.1: + /@babel/plugin-syntax-json-strings/7.8.3_@babel+core@7.19.3: resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-jsx/7.18.6_@babel+core@7.19.1: + /@babel/plugin-syntax-jsx/7.18.6_@babel+core@7.19.3: resolution: {integrity: sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.19.1: + /@babel/plugin-syntax-logical-assignment-operators/7.10.4_@babel+core@7.19.3: resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.19.1: + /@babel/plugin-syntax-nullish-coalescing-operator/7.8.3_@babel+core@7.19.3: resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.19.1: + /@babel/plugin-syntax-numeric-separator/7.10.4_@babel+core@7.19.3: resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.19.1: + /@babel/plugin-syntax-object-rest-spread/7.8.3_@babel+core@7.19.3: resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.19.1: + /@babel/plugin-syntax-optional-catch-binding/7.8.3_@babel+core@7.19.3: resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.19.1: + /@babel/plugin-syntax-optional-chaining/7.8.3_@babel+core@7.19.3: resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.19.1: + /@babel/plugin-syntax-top-level-await/7.14.5_@babel+core@7.19.3: resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true - /@babel/plugin-syntax-typescript/7.18.6_@babel+core@7.19.1: + /@babel/plugin-syntax-typescript/7.18.6_@babel+core@7.19.3: resolution: {integrity: sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@babel/helper-plugin-utils': 7.19.0 dev: true @@ -473,26 +413,8 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/parser': 7.19.1 - '@babel/types': 7.19.0 - dev: true - - /@babel/traverse/7.19.1: - resolution: {integrity: sha512-0j/ZfZMxKukDaag2PtOPDbwuELqIar6lLskVPPJDjXMXjfLb1Obo/1yjxIGqqAJrmfaTIY3z2wFLAQ7qSkLsuA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.18.6 - '@babel/generator': 7.19.0 - '@babel/helper-environment-visitor': 7.18.9 - '@babel/helper-function-name': 7.19.0 - '@babel/helper-hoist-variables': 7.18.6 - '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.19.1 - '@babel/types': 7.19.0 - debug: 4.3.4 - globals: 11.12.0 - transitivePeerDependencies: - - supports-color + '@babel/parser': 7.19.4 + '@babel/types': 7.19.4 dev: true /@babel/traverse/7.19.4: @@ -513,24 +435,6 @@ packages: - supports-color dev: true - /@babel/types/7.19.0: - resolution: {integrity: sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.18.10 - '@babel/helper-validator-identifier': 7.19.1 - to-fast-properties: 2.0.0 - dev: true - - /@babel/types/7.19.3: - resolution: {integrity: sha512-hGCaQzIY22DJlDh9CH7NOxgKkFjBk0Cw9xDO1Xmh2151ti7wiGfQ3LauXzL4HP1fmFlTX6XjpRETTpUcv7wQLw==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.18.10 - '@babel/helper-validator-identifier': 7.19.1 - to-fast-properties: 2.0.0 - dev: true - /@babel/types/7.19.4: resolution: {integrity: sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==} engines: {node: '>=6.9.0'} @@ -724,7 +628,7 @@ packages: '@jest/test-result': 29.0.3 '@jest/transform': 29.0.3 '@jest/types': 29.0.3 - '@jridgewell/trace-mapping': 0.3.15 + '@jridgewell/trace-mapping': 0.3.16 '@types/node': 16.11.62 chalk: 4.1.2 collect-v8-coverage: 1.0.1 @@ -759,7 +663,7 @@ packages: resolution: {integrity: sha512-nOr+0EM8GiHf34mq2GcJyz/gYFyLQ2INDhAylrZJ9mMWoW21mLBfZa0BUVPPMxVYrLjeiRe2Z7kWXOGnS0TFhQ==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@jridgewell/trace-mapping': 0.3.15 + '@jridgewell/trace-mapping': 0.3.16 callsites: 3.1.0 graceful-fs: 4.2.10 dev: true @@ -788,12 +692,12 @@ packages: resolution: {integrity: sha512-C5ihFTRYaGDbi/xbRQRdbo5ddGtI4VSpmL6AIcZxdhwLbXMa7PcXxxqyI91vGOFHnn5aVM3WYnYKCHEqmLVGzg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@jest/types': 29.0.3 - '@jridgewell/trace-mapping': 0.3.15 + '@jridgewell/trace-mapping': 0.3.16 babel-plugin-istanbul: 6.1.1 chalk: 4.1.2 - convert-source-map: 1.8.0 + convert-source-map: 1.9.0 fast-json-stable-stringify: 2.1.0 graceful-fs: 4.2.10 jest-haste-map: 29.0.3 @@ -850,13 +754,6 @@ packages: resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} dev: true - /@jridgewell/trace-mapping/0.3.15: - resolution: {integrity: sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==} - dependencies: - '@jridgewell/resolve-uri': 3.1.0 - '@jridgewell/sourcemap-codec': 1.4.14 - dev: true - /@jridgewell/trace-mapping/0.3.16: resolution: {integrity: sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==} dependencies: @@ -1244,8 +1141,8 @@ packages: /@types/babel__core/7.1.19: resolution: {integrity: sha512-WEOTgRsbYkvA/KCsDwVEGkd7WAr1e3g31VHQ8zy5gul/V1qKullU/BU5I68X5v7V3GnB9eotmom4v5a5gjxorw==} dependencies: - '@babel/parser': 7.19.1 - '@babel/types': 7.19.0 + '@babel/parser': 7.19.4 + '@babel/types': 7.19.4 '@types/babel__generator': 7.6.4 '@types/babel__template': 7.4.1 '@types/babel__traverse': 7.18.1 @@ -1254,20 +1151,20 @@ packages: /@types/babel__generator/7.6.4: resolution: {integrity: sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==} dependencies: - '@babel/types': 7.19.0 + '@babel/types': 7.19.4 dev: true /@types/babel__template/7.4.1: resolution: {integrity: sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==} dependencies: - '@babel/parser': 7.19.1 - '@babel/types': 7.19.0 + '@babel/parser': 7.19.4 + '@babel/types': 7.19.4 dev: true /@types/babel__traverse/7.18.1: resolution: {integrity: sha512-FSdLaZh2UxaMuLp9lixWaHq/golWTRWOnRsAXzDTDSDOQLuZb1nsdCt6pJSPWSEQt2eFZ2YVk3oYhn+1kLMeMA==} dependencies: - '@babel/types': 7.19.0 + '@babel/types': 7.19.4 dev: true /@types/cross-spawn/6.0.2: @@ -1637,17 +1534,17 @@ packages: engines: {node: '>= 4.0.0'} dev: true - /babel-jest/29.0.3_@babel+core@7.19.1: + /babel-jest/29.0.3_@babel+core@7.19.3: resolution: {integrity: sha512-ApPyHSOhS/sVzwUOQIWJmdvDhBsMG01HX9z7ogtkp1TToHGGUWFlnXJUIzCgKPSfiYLn3ibipCYzsKSURHEwLg==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.8.0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@jest/transform': 29.0.3 '@types/babel__core': 7.1.19 babel-plugin-istanbul: 6.1.1 - babel-preset-jest: 29.0.2_@babel+core@7.19.1 + babel-preset-jest: 29.0.2_@babel+core@7.19.3 chalk: 4.1.2 graceful-fs: 4.2.10 slash: 3.0.0 @@ -1673,40 +1570,40 @@ packages: engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: '@babel/template': 7.18.10 - '@babel/types': 7.19.0 + '@babel/types': 7.19.4 '@types/babel__core': 7.1.19 '@types/babel__traverse': 7.18.1 dev: true - /babel-preset-current-node-syntax/1.0.1_@babel+core@7.19.1: + /babel-preset-current-node-syntax/1.0.1_@babel+core@7.19.3: resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.19.1 - '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.19.1 - '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.19.1 - '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.19.1 - '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.19.1 - '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.19.1 - '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.19.1 - '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.19.1 - '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.19.1 - '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.19.1 - '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.19.1 - '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.19.1 - '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.19.1 - dev: true - - /babel-preset-jest/29.0.2_@babel+core@7.19.1: + '@babel/core': 7.19.3 + '@babel/plugin-syntax-async-generators': 7.8.4_@babel+core@7.19.3 + '@babel/plugin-syntax-bigint': 7.8.3_@babel+core@7.19.3 + '@babel/plugin-syntax-class-properties': 7.12.13_@babel+core@7.19.3 + '@babel/plugin-syntax-import-meta': 7.10.4_@babel+core@7.19.3 + '@babel/plugin-syntax-json-strings': 7.8.3_@babel+core@7.19.3 + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4_@babel+core@7.19.3 + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3_@babel+core@7.19.3 + '@babel/plugin-syntax-numeric-separator': 7.10.4_@babel+core@7.19.3 + '@babel/plugin-syntax-object-rest-spread': 7.8.3_@babel+core@7.19.3 + '@babel/plugin-syntax-optional-catch-binding': 7.8.3_@babel+core@7.19.3 + '@babel/plugin-syntax-optional-chaining': 7.8.3_@babel+core@7.19.3 + '@babel/plugin-syntax-top-level-await': 7.14.5_@babel+core@7.19.3 + dev: true + + /babel-preset-jest/29.0.2_@babel+core@7.19.3: resolution: {integrity: sha512-BeVXp7rH5TK96ofyEnHjznjLMQ2nAeDJ+QzxKnHAAMs0RgrQsCywjAN8m4mOm5Di0pxU//3AoEeJJrerMH5UeA==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 babel-plugin-jest-hoist: 29.0.2 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.19.1 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.19.3 dev: true /balanced-match/1.0.2: @@ -2037,12 +1934,6 @@ packages: upper-case: 2.0.2 dev: false - /convert-source-map/1.8.0: - resolution: {integrity: sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==} - dependencies: - safe-buffer: 5.1.2 - dev: true - /convert-source-map/1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} dev: true @@ -2837,8 +2728,8 @@ packages: resolution: {integrity: sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==} engines: {node: '>=8'} dependencies: - '@babel/core': 7.19.1 - '@babel/parser': 7.19.1 + '@babel/core': 7.19.3 + '@babel/parser': 7.19.4 '@istanbuljs/schema': 0.1.3 istanbul-lib-coverage: 3.2.0 semver: 6.3.0 @@ -2949,11 +2840,11 @@ packages: ts-node: optional: true dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@jest/test-sequencer': 29.0.3 '@jest/types': 29.0.3 '@types/node': 14.18.29 - babel-jest: 29.0.3_@babel+core@7.19.1 + babel-jest: 29.0.3_@babel+core@7.19.3 chalk: 4.1.2 ci-info: 3.4.0 deepmerge: 4.2.2 @@ -2989,11 +2880,11 @@ packages: ts-node: optional: true dependencies: - '@babel/core': 7.19.1 + '@babel/core': 7.19.3 '@jest/test-sequencer': 29.0.3 '@jest/types': 29.0.3 '@types/node': 16.11.62 - babel-jest: 29.0.3_@babel+core@7.19.1 + babel-jest: 29.0.3_@babel+core@7.19.3 chalk: 4.1.2 ci-info: 3.4.0 deepmerge: 4.2.2 @@ -3227,18 +3118,18 @@ packages: resolution: {integrity: sha512-52q6JChm04U3deq+mkQ7R/7uy7YyfVIrebMi6ZkBoDJ85yEjm/sJwdr1P0LOIEHmpyLlXrxy3QP0Zf5J2kj0ew==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} dependencies: - '@babel/core': 7.19.1 - '@babel/generator': 7.19.0 - '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.19.1 - '@babel/plugin-syntax-typescript': 7.18.6_@babel+core@7.19.1 - '@babel/traverse': 7.19.1 - '@babel/types': 7.19.0 + '@babel/core': 7.19.3 + '@babel/generator': 7.19.5 + '@babel/plugin-syntax-jsx': 7.18.6_@babel+core@7.19.3 + '@babel/plugin-syntax-typescript': 7.18.6_@babel+core@7.19.3 + '@babel/traverse': 7.19.4 + '@babel/types': 7.19.4 '@jest/expect-utils': 29.0.3 '@jest/transform': 29.0.3 '@jest/types': 29.0.3 '@types/babel__traverse': 7.18.1 '@types/prettier': 2.7.0 - babel-preset-current-node-syntax: 1.0.1_@babel+core@7.19.1 + babel-preset-current-node-syntax: 1.0.1_@babel+core@7.19.3 chalk: 4.1.2 expect: 29.0.3 graceful-fs: 4.2.10 @@ -4702,9 +4593,9 @@ packages: resolution: {integrity: sha512-74Y4LqY74kLE6IFyIjPtkSTWzUZmj8tdHT9Ii/26dvQ6K9Dl2NbEfj0XgU2sHCtKgt5VupqhlO/5aWuqS+IY1w==} engines: {node: '>=10.12.0'} dependencies: - '@jridgewell/trace-mapping': 0.3.15 + '@jridgewell/trace-mapping': 0.3.16 '@types/istanbul-lib-coverage': 2.0.4 - convert-source-map: 1.8.0 + convert-source-map: 1.9.0 dev: true /validate-npm-package-license/3.0.4: From 6a9ee1e87435283b49ce9b1b6cdb13fda11deb09 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Wed, 12 Oct 2022 15:03:45 +0800 Subject: [PATCH 11/15] WIP --- packages/runtime/.gitignore | 1 + packages/runtime/src/handler/data/handler.ts | 302 ++++++++++- .../src/handler/data/query-processor.ts | 53 +- packages/runtime/src/handler/types.ts | 11 + packages/runtime/src/types.ts | 9 + packages/runtime/tests/coverage/clover.xml | 63 --- .../tests/coverage/coverage-final.json | 2 - .../tests/coverage/lcov-report/base.css | 224 -------- .../coverage/lcov-report/block-navigation.js | 87 --- .../tests/coverage/lcov-report/favicon.png | Bin 445 -> 0 bytes .../tests/coverage/lcov-report/index.html | 116 ---- .../tests/coverage/lcov-report/prettify.css | 1 - .../tests/coverage/lcov-report/prettify.js | 2 - .../lcov-report/query-processor.ts.html | 247 --------- .../lcov-report/sort-arrow-sprite.png | Bin 138 -> 0 bytes .../tests/coverage/lcov-report/sorter.js | 196 ------- packages/runtime/tests/coverage/lcov.info | 83 --- .../runtime/tests/query-processor.test.ts | 6 +- .../data => prisma}/expression-writer.ts | 2 +- packages/schema/src/generator/prisma/index.ts | 508 +----------------- .../plain-expression-builder.ts | 2 +- .../generator/prisma/query-gard-generator.ts | 208 +++++++ .../src/generator/prisma/schema-generator.ts | 297 ++++++++++ .../generator/server/data/data-generator.ts | 483 ----------------- .../server/function/function-generator.ts | 32 -- packages/schema/src/generator/server/index.ts | 57 -- .../generator/server/server-code-generator.ts | 6 - packages/schema/src/utils/indent-string.ts | 2 +- .../tests/generator/expression-writer.test.ts | 2 +- samples/todo/.env | 4 +- samples/todo/package.json | 4 +- 31 files changed, 856 insertions(+), 2154 deletions(-) delete mode 100644 packages/runtime/tests/coverage/clover.xml delete mode 100644 packages/runtime/tests/coverage/coverage-final.json delete mode 100644 packages/runtime/tests/coverage/lcov-report/base.css delete mode 100644 packages/runtime/tests/coverage/lcov-report/block-navigation.js delete mode 100644 packages/runtime/tests/coverage/lcov-report/favicon.png delete mode 100644 packages/runtime/tests/coverage/lcov-report/index.html delete mode 100644 packages/runtime/tests/coverage/lcov-report/prettify.css delete mode 100644 packages/runtime/tests/coverage/lcov-report/prettify.js delete mode 100644 packages/runtime/tests/coverage/lcov-report/query-processor.ts.html delete mode 100644 packages/runtime/tests/coverage/lcov-report/sort-arrow-sprite.png delete mode 100644 packages/runtime/tests/coverage/lcov-report/sorter.js delete mode 100644 packages/runtime/tests/coverage/lcov.info rename packages/schema/src/generator/{server/data => prisma}/expression-writer.ts (99%) rename packages/schema/src/generator/{server/data => prisma}/plain-expression-builder.ts (98%) create mode 100644 packages/schema/src/generator/prisma/query-gard-generator.ts create mode 100644 packages/schema/src/generator/prisma/schema-generator.ts delete mode 100644 packages/schema/src/generator/server/data/data-generator.ts delete mode 100644 packages/schema/src/generator/server/function/function-generator.ts delete mode 100644 packages/schema/src/generator/server/index.ts delete mode 100644 packages/schema/src/generator/server/server-code-generator.ts diff --git a/packages/runtime/.gitignore b/packages/runtime/.gitignore index 502167fa0..0d39dd036 100644 --- a/packages/runtime/.gitignore +++ b/packages/runtime/.gitignore @@ -1 +1,2 @@ /lib +/tests/coverage/ diff --git a/packages/runtime/src/handler/data/handler.ts b/packages/runtime/src/handler/data/handler.ts index 419e2bdd6..ca9cee526 100644 --- a/packages/runtime/src/handler/data/handler.ts +++ b/packages/runtime/src/handler/data/handler.ts @@ -1,9 +1,19 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { RequestHandlerOptions } from '../../request-handler'; -import { QueryContext, Service } from '../../types'; -import { RequestHandler } from '../types'; +import { + PolicyOperationKind, + QueryContext, + ServerErrorCode, + Service, +} from '../../types'; +import { RequestHandler, RequestHandlerError } from '../types'; import { QueryProcessor } from './query-processor'; +const PRISMA_ERROR_MAPPING: Record = { + P2002: ServerErrorCode.UNIQUE_CONSTRAINT_VIOLATION, + P2003: ServerErrorCode.REFERENCE_CONSTRAINT_VIOLATION, +}; + export default class DataHandler implements RequestHandler { private readonly queryProcessor: QueryProcessor; @@ -20,22 +30,62 @@ export default class DataHandler implements RequestHandler { const context = { user: await this.options.getServerUser(req, res) }; - switch (method) { - case 'GET': - this.get(req, res, model, id, context); - break; + try { + switch (method) { + case 'GET': + await this.get(req, res, model, id, context); + break; + + case 'POST': + await this.post(req, res, model, context); + break; - case 'POST': - this.post(req, res, model, context); - break; + case 'PUT': + await this.put(req, res, model, id, context); + break; - case 'PUT': - this.put(req, res, model, id, context); - break; + case 'DELETE': + await this.del(req, res, model, id, context); + break; - case 'DELETE': - this.del(req, res, model, id, context); - break; + default: + console.warn(`Unhandled method: ${method}`); + res.status(200).send({}); + break; + } + } catch (err: any) { + console.error(`Error handling ${method} ${model}: ${err}`); + if (err instanceof RequestHandlerError) { + switch (err.code) { + case ServerErrorCode.DENIED_BY_POLICY: + res.status(403).send({ + code: err.code, + message: err.message, + }); + break; + case ServerErrorCode.ENTITY_NOT_FOUND: + res.status(404).send({ + code: err.code, + message: err.message, + }); + break; + default: + res.status(400).send({ + code: err.code, + message: err.message, + }); + } + } else if (err.code && PRISMA_ERROR_MAPPING[err.code]) { + res.status(400).send({ + code: PRISMA_ERROR_MAPPING[err.code], + message: 'database access error', + }); + } else { + console.error( + `An unknown error occurred: ${JSON.stringify(err)}` + ); + res.status(500).send({ error: ServerErrorCode.UNKNOWN }); + } } } @@ -66,13 +116,18 @@ export default class DataHandler implements RequestHandler { } r = await db.findFirst(processedArgs); if (!r) { - res.status(404).send({ error: `${model} not found` }); - return; + throw new RequestHandlerError( + ServerErrorCode.ENTITY_NOT_FOUND, + 'not found' + ); } } else { r = await db.findMany(processedArgs); } + console.log( + `Finding ${model}:\n${JSON.stringify(processedArgs, undefined, 2)}` + ); await this.queryProcessor.postProcess( model, processedArgs, @@ -84,32 +139,233 @@ export default class DataHandler implements RequestHandler { res.status(200).send(r); } - private post( + private async post( req: NextApiRequest, res: NextApiResponse, model: string, context: QueryContext ) { - throw new Error('Function not implemented.'); + const args = req.body; + if (!args) { + throw new RequestHandlerError( + ServerErrorCode.INVALID_REQUEST_PARAMS, + 'body is required' + ); + } + + const db = this.service.db as any; + const processedArgs = await this.queryProcessor.processQueryArgs( + model, + args, + 'create', + context, + false + ); + + const r = await db.$transaction(async (tx: any) => { + console.log( + `Create ${model}:\n${JSON.stringify( + processedArgs, + undefined, + 2 + )}` + ); + const created = await tx[model].create(processedArgs); + + let queryArgs = { + where: { id: created.id }, + include: args.include, + select: args.select, + }; + queryArgs = await this.queryProcessor.processQueryArgs( + model, + queryArgs, + 'create', + context + ); + console.log( + `Finding created ${model}:\n${JSON.stringify( + queryArgs, + undefined, + 2 + )}` + ); + const found = await tx[model].findFirst(queryArgs); + if (!found) { + throw new RequestHandlerError( + ServerErrorCode.DENIED_BY_POLICY, + 'denied by policy' + ); + } + + return created; + }); + + await this.queryProcessor.postProcess( + model, + processedArgs, + r, + 'create', + context + ); + res.status(201).send(r); } - private put( + private async put( req: NextApiRequest, res: NextApiResponse, model: string, id: string, context: QueryContext ) { - throw new Error('Function not implemented.'); + if (!id) { + throw new RequestHandlerError( + ServerErrorCode.INVALID_REQUEST_PARAMS, + 'missing "id" parameter' + ); + } + + // ensure entity passes policy check + await this.ensureEntityPolicy(id, model, 'update', context); + + const args = req.body; + if (!args) { + throw new RequestHandlerError( + ServerErrorCode.INVALID_REQUEST_PARAMS, + 'body is required' + ); + } + + const db = this.service.db as any; + const updateArgs = await this.queryProcessor.processQueryArgs( + model, + args, + 'update', + context, + false + ); + updateArgs.where = { ...updateArgs.where, id }; + + const r = await db.$transaction(async (tx: any) => { + console.log( + `Update ${model}:\n${JSON.stringify(updateArgs, undefined, 2)}` + ); + const updated = await tx[model].update(updateArgs); + + // make sure after update, the entity passes policy check + let queryArgs = { + where: updateArgs.where, + include: args.include, + select: args.select, + }; + queryArgs = await this.queryProcessor.processQueryArgs( + model, + queryArgs, + 'update', + context + ); + console.log( + `Finding post-updated ${model}:\n${JSON.stringify( + queryArgs, + undefined, + 2 + )}` + ); + const found = await tx[model].findFirst(queryArgs); + if (!found) { + throw new RequestHandlerError( + ServerErrorCode.DENIED_BY_POLICY, + 'post-update denied by policy' + ); + } + + return updated; + }); + + await this.queryProcessor.postProcess( + model, + updateArgs, + r, + 'update', + context + ); + res.status(200).send(r); } - private del( + private async del( req: NextApiRequest, res: NextApiResponse, model: string, id: string, context: QueryContext ) { - throw new Error('Function not implemented.'); + if (!id) { + throw new RequestHandlerError( + ServerErrorCode.INVALID_REQUEST_PARAMS, + 'missing "id" parameter' + ); + } + + // ensure entity passes policy check + await this.ensureEntityPolicy(id, model, 'delete', context); + + const args = req.query.q ? JSON.parse(req.query.q as string) : {}; + + // proceed with deleting + const delArgs = await this.queryProcessor.processQueryArgs( + model, + args, + 'delete', + context, + false + ); + delArgs.where = { ...delArgs.where, id }; + + console.log( + `Deleting ${model}:\n${JSON.stringify(delArgs, undefined, 2)}` + ); + const db = (this.service.db as any)[model]; + const r = await db.delete(delArgs); + await this.queryProcessor.postProcess( + model, + delArgs, + r, + 'delete', + context + ); + + res.status(200).send(r); + } + + private async ensureEntityPolicy( + id: string, + model: string, + operation: PolicyOperationKind, + context: QueryContext + ) { + const db = (this.service.db as any)[model]; + + // check if the record is readable concerning "delete" policy + const readArgs = await this.queryProcessor.processQueryArgs( + model, + { where: { id } }, + operation, + context + ); + console.log( + `Finding to-be-deleted ${model}:\n${JSON.stringify( + readArgs, + undefined, + 2 + )}` + ); + const read = await db.findFirst(readArgs); + if (!read) { + throw new RequestHandlerError( + ServerErrorCode.DENIED_BY_POLICY, + 'denied by policy' + ); + } + return read; } } diff --git a/packages/runtime/src/handler/data/query-processor.ts b/packages/runtime/src/handler/data/query-processor.ts index c49e807b1..f2dc77679 100644 --- a/packages/runtime/src/handler/data/query-processor.ts +++ b/packages/runtime/src/handler/data/query-processor.ts @@ -8,17 +8,25 @@ export class QueryProcessor { model: string, args: any, operation: PolicyOperationKind, - context: QueryContext + context: QueryContext, + injectWhere: boolean = true ) { const r = args ? deepcopy(args) : {}; - const guard = this.service.buildQueryGuard(model, operation, context); - if (guard) { - if (!r.where) { - r.where = guard; - } else { - r.where = { - AND: [guard, r.where], - }; + + if (injectWhere) { + const guard = await this.service.buildQueryGuard( + model, + operation, + context + ); + if (guard) { + if (!r.where) { + r.where = guard; + } else { + r.where = { + AND: [guard, r.where], + }; + } } } @@ -27,16 +35,23 @@ export class QueryProcessor { const selector = r.include ? 'include' : 'select'; for (const [field, value] of Object.entries(r[selector])) { const fieldInfo = await this.service.resolveField(model, field); - if (fieldInfo && fieldInfo.isArray) { - // note that Prisma only allows to attach filter for "to-many" relation - // query, so we need to handle "to-one" filter separately in post-processing - const fieldGuard = await this.processQueryArgs( - fieldInfo.type, - value === true ? {} : value, - operation, - context - ); - r[selector][field] = fieldGuard; + if (fieldInfo) { + if (fieldInfo.isArray) { + // note that Prisma only allows to attach filter for "to-many" relation + // query, so we need to handle "to-one" filter separately in post-processing + const fieldGuard = await this.processQueryArgs( + fieldInfo.type, + value === true ? {} : value, + operation, + context + ); + r[selector][field] = fieldGuard; + } else { + // make sure "id" field is included so that we can do post-process filtering + if (selector === 'select') { + r[selector].id = true; + } + } } } } diff --git a/packages/runtime/src/handler/types.ts b/packages/runtime/src/handler/types.ts index 3d9f75e1d..b927ad31e 100644 --- a/packages/runtime/src/handler/types.ts +++ b/packages/runtime/src/handler/types.ts @@ -1,4 +1,5 @@ import { NextApiRequest, NextApiResponse } from 'next'; +import { ServerErrorCode } from '../types'; export interface RequestHandler { handle( @@ -7,3 +8,13 @@ export interface RequestHandler { path: string[] ): Promise; } + +export class RequestHandlerError extends Error { + constructor(public readonly code: ServerErrorCode, message: string) { + super(message); + } + + toString() { + return `Request handler error: ${this.code}, ${this.message}`; + } +} diff --git a/packages/runtime/src/types.ts b/packages/runtime/src/types.ts index bdcb2f770..5387800ea 100644 --- a/packages/runtime/src/types.ts +++ b/packages/runtime/src/types.ts @@ -29,3 +29,12 @@ export interface Service { context: QueryContext ): any; } + +export enum ServerErrorCode { + ENTITY_NOT_FOUND = 'ENTITY_NOT_FOUND', + INVALID_REQUEST_PARAMS = 'INVALID_REQUEST_PARAMS', + DENIED_BY_POLICY = 'DENIED_BY_POLICY', + UNIQUE_CONSTRAINT_VIOLATION = 'UNIQUE_CONSTRAINT_VIOLATION', + REFERENCE_CONSTRAINT_VIOLATION = 'REFERENCE_CONSTRAINT_VIOLATION', + UNKNOWN = 'UNKNOWN', +} diff --git a/packages/runtime/tests/coverage/clover.xml b/packages/runtime/tests/coverage/clover.xml deleted file mode 100644 index 1e2768eb0..000000000 --- a/packages/runtime/tests/coverage/clover.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/packages/runtime/tests/coverage/coverage-final.json b/packages/runtime/tests/coverage/coverage-final.json deleted file mode 100644 index 75403130f..000000000 --- a/packages/runtime/tests/coverage/coverage-final.json +++ /dev/null @@ -1,2 +0,0 @@ -{"/Users/yiming/git/zenstack/zenstack/packages/runtime/src/handler/data/query-processor.ts": {"path":"/Users/yiming/git/zenstack/zenstack/packages/runtime/src/handler/data/query-processor.ts","all":false,"statementMap":{"0":{"start":{"line":1,"column":0},"end":{"line":1,"column":32}},"1":{"start":{"line":2,"column":0},"end":{"line":2,"column":73}},"2":{"start":{"line":3,"column":0},"end":{"line":3,"column":0}},"3":{"start":{"line":4,"column":0},"end":{"line":4,"column":29}},"4":{"start":{"line":5,"column":0},"end":{"line":5,"column":53}},"5":{"start":{"line":6,"column":0},"end":{"line":6,"column":0}},"6":{"start":{"line":7,"column":0},"end":{"line":7,"column":27}},"7":{"start":{"line":8,"column":0},"end":{"line":8,"column":22}},"8":{"start":{"line":9,"column":0},"end":{"line":9,"column":18}},"9":{"start":{"line":10,"column":0},"end":{"line":10,"column":39}},"10":{"start":{"line":11,"column":0},"end":{"line":11,"column":29}},"11":{"start":{"line":12,"column":0},"end":{"line":12,"column":7}},"12":{"start":{"line":13,"column":0},"end":{"line":13,"column":45}},"13":{"start":{"line":14,"column":0},"end":{"line":14,"column":78}},"14":{"start":{"line":15,"column":0},"end":{"line":15,"column":20}},"15":{"start":{"line":16,"column":0},"end":{"line":16,"column":27}},"16":{"start":{"line":17,"column":0},"end":{"line":17,"column":32}},"17":{"start":{"line":18,"column":0},"end":{"line":18,"column":20}},"18":{"start":{"line":19,"column":0},"end":{"line":19,"column":27}},"19":{"start":{"line":20,"column":0},"end":{"line":20,"column":42}},"20":{"start":{"line":21,"column":0},"end":{"line":21,"column":18}},"21":{"start":{"line":22,"column":0},"end":{"line":22,"column":13}},"22":{"start":{"line":23,"column":0},"end":{"line":23,"column":9}},"23":{"start":{"line":24,"column":0},"end":{"line":24,"column":0}},"24":{"start":{"line":25,"column":0},"end":{"line":25,"column":36}},"25":{"start":{"line":26,"column":0},"end":{"line":26,"column":60}},"26":{"start":{"line":27,"column":0},"end":{"line":27,"column":62}},"27":{"start":{"line":28,"column":0},"end":{"line":28,"column":71}},"28":{"start":{"line":29,"column":0},"end":{"line":29,"column":80}},"29":{"start":{"line":30,"column":0},"end":{"line":30,"column":53}},"30":{"start":{"line":31,"column":0},"end":{"line":31,"column":91}},"31":{"start":{"line":32,"column":0},"end":{"line":32,"column":96}},"32":{"start":{"line":33,"column":0},"end":{"line":33,"column":67}},"33":{"start":{"line":34,"column":0},"end":{"line":34,"column":39}},"34":{"start":{"line":35,"column":0},"end":{"line":35,"column":52}},"35":{"start":{"line":36,"column":0},"end":{"line":36,"column":34}},"36":{"start":{"line":37,"column":0},"end":{"line":37,"column":31}},"37":{"start":{"line":38,"column":0},"end":{"line":38,"column":22}},"38":{"start":{"line":39,"column":0},"end":{"line":39,"column":52}},"39":{"start":{"line":40,"column":0},"end":{"line":40,"column":17}},"40":{"start":{"line":41,"column":0},"end":{"line":41,"column":13}},"41":{"start":{"line":42,"column":0},"end":{"line":42,"column":9}},"42":{"start":{"line":43,"column":0},"end":{"line":43,"column":0}},"43":{"start":{"line":44,"column":0},"end":{"line":44,"column":17}},"44":{"start":{"line":45,"column":0},"end":{"line":45,"column":5}},"45":{"start":{"line":46,"column":0},"end":{"line":46,"column":0}},"46":{"start":{"line":47,"column":0},"end":{"line":47,"column":22}},"47":{"start":{"line":48,"column":0},"end":{"line":48,"column":22}},"48":{"start":{"line":49,"column":0},"end":{"line":49,"column":23}},"49":{"start":{"line":50,"column":0},"end":{"line":50,"column":18}},"50":{"start":{"line":51,"column":0},"end":{"line":51,"column":39}},"51":{"start":{"line":52,"column":0},"end":{"line":52,"column":29}},"52":{"start":{"line":53,"column":0},"end":{"line":53,"column":8}},"53":{"start":{"line":54,"column":0},"end":{"line":54,"column":1}}},"s":{"0":1,"1":1,"2":1,"3":1,"4":1,"5":1,"6":1,"7":12,"8":12,"9":12,"10":12,"11":12,"12":12,"13":12,"14":12,"15":12,"16":9,"17":12,"18":3,"19":3,"20":3,"21":3,"22":12,"23":12,"24":12,"25":6,"26":6,"27":6,"28":8,"29":8,"30":4,"31":4,"32":4,"33":4,"34":4,"35":4,"36":4,"37":4,"38":4,"39":4,"40":8,"41":6,"42":12,"43":12,"44":12,"45":1,"46":1,"47":0,"48":0,"49":0,"50":0,"51":0,"52":0,"53":1},"branchMap":{"0":{"type":"branch","line":5,"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":53}},"locations":[{"start":{"line":5,"column":4},"end":{"line":5,"column":53}}]},"1":{"type":"branch","line":7,"loc":{"start":{"line":7,"column":10},"end":{"line":45,"column":5}},"locations":[{"start":{"line":7,"column":10},"end":{"line":45,"column":5}}]},"2":{"type":"branch","line":13,"loc":{"start":{"line":13,"column":40},"end":{"line":13,"column":44}},"locations":[{"start":{"line":13,"column":40},"end":{"line":13,"column":44}}]},"3":{"type":"branch","line":16,"loc":{"start":{"line":16,"column":26},"end":{"line":18,"column":19}},"locations":[{"start":{"line":16,"column":26},"end":{"line":18,"column":19}}]},"4":{"type":"branch","line":18,"loc":{"start":{"line":18,"column":13},"end":{"line":22,"column":13}},"locations":[{"start":{"line":18,"column":13},"end":{"line":22,"column":13}}]},"5":{"type":"branch","line":25,"loc":{"start":{"line":25,"column":21},"end":{"line":25,"column":33}},"locations":[{"start":{"line":25,"column":21},"end":{"line":25,"column":33}}]},"6":{"type":"branch","line":25,"loc":{"start":{"line":25,"column":35},"end":{"line":42,"column":9}},"locations":[{"start":{"line":25,"column":35},"end":{"line":42,"column":9}}]},"7":{"type":"branch","line":27,"loc":{"start":{"line":27,"column":39},"end":{"line":27,"column":50}},"locations":[{"start":{"line":27,"column":39},"end":{"line":27,"column":50}}]},"8":{"type":"branch","line":27,"loc":{"start":{"line":27,"column":51},"end":{"line":27,"column":61}},"locations":[{"start":{"line":27,"column":51},"end":{"line":27,"column":61}}]},"9":{"type":"branch","line":28,"loc":{"start":{"line":28,"column":70},"end":{"line":41,"column":13}},"locations":[{"start":{"line":28,"column":70},"end":{"line":41,"column":13}}]},"10":{"type":"branch","line":30,"loc":{"start":{"line":30,"column":29},"end":{"line":30,"column":50}},"locations":[{"start":{"line":30,"column":29},"end":{"line":30,"column":50}}]},"11":{"type":"branch","line":30,"loc":{"start":{"line":30,"column":52},"end":{"line":40,"column":17}},"locations":[{"start":{"line":30,"column":52},"end":{"line":40,"column":17}}]},"12":{"type":"branch","line":35,"loc":{"start":{"line":35,"column":39},"end":{"line":35,"column":43}},"locations":[{"start":{"line":35,"column":39},"end":{"line":35,"column":43}}]},"13":{"type":"branch","line":35,"loc":{"start":{"line":35,"column":44},"end":{"line":35,"column":51}},"locations":[{"start":{"line":35,"column":44},"end":{"line":35,"column":51}}]}},"b":{"0":[1],"1":[12],"2":[0],"3":[9],"4":[3],"5":[9],"6":[6],"7":[3],"8":[3],"9":[8],"10":[6],"11":[4],"12":[2],"13":[2]},"fnMap":{"0":{"name":"QueryProcessor","decl":{"start":{"line":5,"column":4},"end":{"line":5,"column":53}},"loc":{"start":{"line":5,"column":4},"end":{"line":5,"column":53}},"line":5},"1":{"name":"processQueryArgs","decl":{"start":{"line":7,"column":10},"end":{"line":45,"column":5}},"loc":{"start":{"line":7,"column":10},"end":{"line":45,"column":5}},"line":7},"2":{"name":"postProcess","decl":{"start":{"line":47,"column":10},"end":{"line":53,"column":8}},"loc":{"start":{"line":47,"column":10},"end":{"line":53,"column":8}},"line":47}},"f":{"0":1,"1":12,"2":0}} -} diff --git a/packages/runtime/tests/coverage/lcov-report/base.css b/packages/runtime/tests/coverage/lcov-report/base.css deleted file mode 100644 index f418035b4..000000000 --- a/packages/runtime/tests/coverage/lcov-report/base.css +++ /dev/null @@ -1,224 +0,0 @@ -body, html { - margin:0; padding: 0; - height: 100%; -} -body { - font-family: Helvetica Neue, Helvetica, Arial; - font-size: 14px; - color:#333; -} -.small { font-size: 12px; } -*, *:after, *:before { - -webkit-box-sizing:border-box; - -moz-box-sizing:border-box; - box-sizing:border-box; - } -h1 { font-size: 20px; margin: 0;} -h2 { font-size: 14px; } -pre { - font: 12px/1.4 Consolas, "Liberation Mono", Menlo, Courier, monospace; - margin: 0; - padding: 0; - -moz-tab-size: 2; - -o-tab-size: 2; - tab-size: 2; -} -a { color:#0074D9; text-decoration:none; } -a:hover { text-decoration:underline; } -.strong { font-weight: bold; } -.space-top1 { padding: 10px 0 0 0; } -.pad2y { padding: 20px 0; } -.pad1y { padding: 10px 0; } -.pad2x { padding: 0 20px; } -.pad2 { padding: 20px; } -.pad1 { padding: 10px; } -.space-left2 { padding-left:55px; } -.space-right2 { padding-right:20px; } -.center { text-align:center; } -.clearfix { display:block; } -.clearfix:after { - content:''; - display:block; - height:0; - clear:both; - visibility:hidden; - } -.fl { float: left; } -@media only screen and (max-width:640px) { - .col3 { width:100%; max-width:100%; } - .hide-mobile { display:none!important; } -} - -.quiet { - color: #7f7f7f; - color: rgba(0,0,0,0.5); -} -.quiet a { opacity: 0.7; } - -.fraction { - font-family: Consolas, 'Liberation Mono', Menlo, Courier, monospace; - font-size: 10px; - color: #555; - background: #E8E8E8; - padding: 4px 5px; - border-radius: 3px; - vertical-align: middle; -} - -div.path a:link, div.path a:visited { color: #333; } -table.coverage { - border-collapse: collapse; - margin: 10px 0 0 0; - padding: 0; -} - -table.coverage td { - margin: 0; - padding: 0; - vertical-align: top; -} -table.coverage td.line-count { - text-align: right; - padding: 0 5px 0 20px; -} -table.coverage td.line-coverage { - text-align: right; - padding-right: 10px; - min-width:20px; -} - -table.coverage td span.cline-any { - display: inline-block; - padding: 0 5px; - width: 100%; -} -.missing-if-branch { - display: inline-block; - margin-right: 5px; - border-radius: 3px; - position: relative; - padding: 0 4px; - background: #333; - color: yellow; -} - -.skip-if-branch { - display: none; - margin-right: 10px; - position: relative; - padding: 0 4px; - background: #ccc; - color: white; -} -.missing-if-branch .typ, .skip-if-branch .typ { - color: inherit !important; -} -.coverage-summary { - border-collapse: collapse; - width: 100%; -} -.coverage-summary tr { border-bottom: 1px solid #bbb; } -.keyline-all { border: 1px solid #ddd; } -.coverage-summary td, .coverage-summary th { padding: 10px; } -.coverage-summary tbody { border: 1px solid #bbb; } -.coverage-summary td { border-right: 1px solid #bbb; } -.coverage-summary td:last-child { border-right: none; } -.coverage-summary th { - text-align: left; - font-weight: normal; - white-space: nowrap; -} -.coverage-summary th.file { border-right: none !important; } -.coverage-summary th.pct { } -.coverage-summary th.pic, -.coverage-summary th.abs, -.coverage-summary td.pct, -.coverage-summary td.abs { text-align: right; } -.coverage-summary td.file { white-space: nowrap; } -.coverage-summary td.pic { min-width: 120px !important; } -.coverage-summary tfoot td { } - -.coverage-summary .sorter { - height: 10px; - width: 7px; - display: inline-block; - margin-left: 0.5em; - background: url(sort-arrow-sprite.png) no-repeat scroll 0 0 transparent; -} -.coverage-summary .sorted .sorter { - background-position: 0 -20px; -} -.coverage-summary .sorted-desc .sorter { - background-position: 0 -10px; -} -.status-line { height: 10px; } -/* yellow */ -.cbranch-no { background: yellow !important; color: #111; } -/* dark red */ -.red.solid, .status-line.low, .low .cover-fill { background:#C21F39 } -.low .chart { border:1px solid #C21F39 } -.highlighted, -.highlighted .cstat-no, .highlighted .fstat-no, .highlighted .cbranch-no{ - background: #C21F39 !important; -} -/* medium red */ -.cstat-no, .fstat-no, .cbranch-no, .cbranch-no { background:#F6C6CE } -/* light red */ -.low, .cline-no { background:#FCE1E5 } -/* light green */ -.high, .cline-yes { background:rgb(230,245,208) } -/* medium green */ -.cstat-yes { background:rgb(161,215,106) } -/* dark green */ -.status-line.high, .high .cover-fill { background:rgb(77,146,33) } -.high .chart { border:1px solid rgb(77,146,33) } -/* dark yellow (gold) */ -.status-line.medium, .medium .cover-fill { background: #f9cd0b; } -.medium .chart { border:1px solid #f9cd0b; } -/* light yellow */ -.medium { background: #fff4c2; } - -.cstat-skip { background: #ddd; color: #111; } -.fstat-skip { background: #ddd; color: #111 !important; } -.cbranch-skip { background: #ddd !important; color: #111; } - -span.cline-neutral { background: #eaeaea; } - -.coverage-summary td.empty { - opacity: .5; - padding-top: 4px; - padding-bottom: 4px; - line-height: 1; - color: #888; -} - -.cover-fill, .cover-empty { - display:inline-block; - height: 12px; -} -.chart { - line-height: 0; -} -.cover-empty { - background: white; -} -.cover-full { - border-right: none !important; -} -pre.prettyprint { - border: none !important; - padding: 0 !important; - margin: 0 !important; -} -.com { color: #999 !important; } -.ignore-none { color: #999; font-weight: normal; } - -.wrapper { - min-height: 100%; - height: auto !important; - height: 100%; - margin: 0 auto -48px; -} -.footer, .push { - height: 48px; -} diff --git a/packages/runtime/tests/coverage/lcov-report/block-navigation.js b/packages/runtime/tests/coverage/lcov-report/block-navigation.js deleted file mode 100644 index cc1213023..000000000 --- a/packages/runtime/tests/coverage/lcov-report/block-navigation.js +++ /dev/null @@ -1,87 +0,0 @@ -/* eslint-disable */ -var jumpToCode = (function init() { - // Classes of code we would like to highlight in the file view - var missingCoverageClasses = ['.cbranch-no', '.cstat-no', '.fstat-no']; - - // Elements to highlight in the file listing view - var fileListingElements = ['td.pct.low']; - - // We don't want to select elements that are direct descendants of another match - var notSelector = ':not(' + missingCoverageClasses.join('):not(') + ') > '; // becomes `:not(a):not(b) > ` - - // Selecter that finds elements on the page to which we can jump - var selector = - fileListingElements.join(', ') + - ', ' + - notSelector + - missingCoverageClasses.join(', ' + notSelector); // becomes `:not(a):not(b) > a, :not(a):not(b) > b` - - // The NodeList of matching elements - var missingCoverageElements = document.querySelectorAll(selector); - - var currentIndex; - - function toggleClass(index) { - missingCoverageElements - .item(currentIndex) - .classList.remove('highlighted'); - missingCoverageElements.item(index).classList.add('highlighted'); - } - - function makeCurrent(index) { - toggleClass(index); - currentIndex = index; - missingCoverageElements.item(index).scrollIntoView({ - behavior: 'smooth', - block: 'center', - inline: 'center' - }); - } - - function goToPrevious() { - var nextIndex = 0; - if (typeof currentIndex !== 'number' || currentIndex === 0) { - nextIndex = missingCoverageElements.length - 1; - } else if (missingCoverageElements.length > 1) { - nextIndex = currentIndex - 1; - } - - makeCurrent(nextIndex); - } - - function goToNext() { - var nextIndex = 0; - - if ( - typeof currentIndex === 'number' && - currentIndex < missingCoverageElements.length - 1 - ) { - nextIndex = currentIndex + 1; - } - - makeCurrent(nextIndex); - } - - return function jump(event) { - if ( - document.getElementById('fileSearch') === document.activeElement && - document.activeElement != null - ) { - // if we're currently focused on the search input, we don't want to navigate - return; - } - - switch (event.which) { - case 78: // n - case 74: // j - goToNext(); - break; - case 66: // b - case 75: // k - case 80: // p - goToPrevious(); - break; - } - }; -})(); -window.addEventListener('keydown', jumpToCode); diff --git a/packages/runtime/tests/coverage/lcov-report/favicon.png b/packages/runtime/tests/coverage/lcov-report/favicon.png deleted file mode 100644 index c1525b811a167671e9de1fa78aab9f5c0b61cef7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 445 zcmV;u0Yd(XP))rP{nL}Ln%S7`m{0DjX9TLF* zFCb$4Oi7vyLOydb!7n&^ItCzb-%BoB`=x@N2jll2Nj`kauio%aw_@fe&*}LqlFT43 z8doAAe))z_%=P%v^@JHp3Hjhj^6*Kr_h|g_Gr?ZAa&y>wxHE99Gk>A)2MplWz2xdG zy8VD2J|Uf#EAw*bo5O*PO_}X2Tob{%bUoO2G~T`@%S6qPyc}VkhV}UifBuRk>%5v( z)x7B{I~z*k<7dv#5tC+m{km(D087J4O%+<<;K|qwefb6@GSX45wCK}Sn*> - - - - Code coverage report for All files - - - - - - - - - -
    -
    -

    All files

    -
    - -
    - 88.88% - Statements - 48/54 -
    - - -
    - 92.85% - Branches - 13/14 -
    - - -
    - 66.66% - Functions - 2/3 -
    - - -
    - 88.88% - Lines - 48/54 -
    - - -
    -

    - Press n or j to go to the next uncovered block, b, p or k for the previous block. -

    - -
    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    FileStatementsBranchesFunctionsLines
    query-processor.ts -
    -
    88.88%48/5492.85%13/1466.66%2/388.88%48/54
    -
    -
    -
    - - - - - - - - \ No newline at end of file diff --git a/packages/runtime/tests/coverage/lcov-report/prettify.css b/packages/runtime/tests/coverage/lcov-report/prettify.css deleted file mode 100644 index b317a7cda..000000000 --- a/packages/runtime/tests/coverage/lcov-report/prettify.css +++ /dev/null @@ -1 +0,0 @@ -.pln{color:#000}@media screen{.str{color:#080}.kwd{color:#008}.com{color:#800}.typ{color:#606}.lit{color:#066}.pun,.opn,.clo{color:#660}.tag{color:#008}.atn{color:#606}.atv{color:#080}.dec,.var{color:#606}.fun{color:red}}@media print,projection{.str{color:#060}.kwd{color:#006;font-weight:bold}.com{color:#600;font-style:italic}.typ{color:#404;font-weight:bold}.lit{color:#044}.pun,.opn,.clo{color:#440}.tag{color:#006;font-weight:bold}.atn{color:#404}.atv{color:#060}}pre.prettyprint{padding:2px;border:1px solid #888}ol.linenums{margin-top:0;margin-bottom:0}li.L0,li.L1,li.L2,li.L3,li.L5,li.L6,li.L7,li.L8{list-style-type:none}li.L1,li.L3,li.L5,li.L7,li.L9{background:#eee} diff --git a/packages/runtime/tests/coverage/lcov-report/prettify.js b/packages/runtime/tests/coverage/lcov-report/prettify.js deleted file mode 100644 index b3225238f..000000000 --- a/packages/runtime/tests/coverage/lcov-report/prettify.js +++ /dev/null @@ -1,2 +0,0 @@ -/* eslint-disable */ -window.PR_SHOULD_USE_CONTINUATION=true;(function(){var h=["break,continue,do,else,for,if,return,while"];var u=[h,"auto,case,char,const,default,double,enum,extern,float,goto,int,long,register,short,signed,sizeof,static,struct,switch,typedef,union,unsigned,void,volatile"];var p=[u,"catch,class,delete,false,import,new,operator,private,protected,public,this,throw,true,try,typeof"];var l=[p,"alignof,align_union,asm,axiom,bool,concept,concept_map,const_cast,constexpr,decltype,dynamic_cast,explicit,export,friend,inline,late_check,mutable,namespace,nullptr,reinterpret_cast,static_assert,static_cast,template,typeid,typename,using,virtual,where"];var x=[p,"abstract,boolean,byte,extends,final,finally,implements,import,instanceof,null,native,package,strictfp,super,synchronized,throws,transient"];var R=[x,"as,base,by,checked,decimal,delegate,descending,dynamic,event,fixed,foreach,from,group,implicit,in,interface,internal,into,is,lock,object,out,override,orderby,params,partial,readonly,ref,sbyte,sealed,stackalloc,string,select,uint,ulong,unchecked,unsafe,ushort,var"];var r="all,and,by,catch,class,else,extends,false,finally,for,if,in,is,isnt,loop,new,no,not,null,of,off,on,or,return,super,then,true,try,unless,until,when,while,yes";var w=[p,"debugger,eval,export,function,get,null,set,undefined,var,with,Infinity,NaN"];var s="caller,delete,die,do,dump,elsif,eval,exit,foreach,for,goto,if,import,last,local,my,next,no,our,print,package,redo,require,sub,undef,unless,until,use,wantarray,while,BEGIN,END";var I=[h,"and,as,assert,class,def,del,elif,except,exec,finally,from,global,import,in,is,lambda,nonlocal,not,or,pass,print,raise,try,with,yield,False,True,None"];var f=[h,"alias,and,begin,case,class,def,defined,elsif,end,ensure,false,in,module,next,nil,not,or,redo,rescue,retry,self,super,then,true,undef,unless,until,when,yield,BEGIN,END"];var H=[h,"case,done,elif,esac,eval,fi,function,in,local,set,then,until"];var A=[l,R,w,s+I,f,H];var e=/^(DIR|FILE|vector|(de|priority_)?queue|list|stack|(const_)?iterator|(multi)?(set|map)|bitset|u?(int|float)\d*)/;var C="str";var z="kwd";var j="com";var O="typ";var G="lit";var L="pun";var F="pln";var m="tag";var E="dec";var J="src";var P="atn";var n="atv";var N="nocode";var M="(?:^^\\.?|[+-]|\\!|\\!=|\\!==|\\#|\\%|\\%=|&|&&|&&=|&=|\\(|\\*|\\*=|\\+=|\\,|\\-=|\\->|\\/|\\/=|:|::|\\;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\@|\\[|\\^|\\^=|\\^\\^|\\^\\^=|\\{|\\||\\|=|\\|\\||\\|\\|=|\\~|break|case|continue|delete|do|else|finally|instanceof|return|throw|try|typeof)\\s*";function k(Z){var ad=0;var S=false;var ac=false;for(var V=0,U=Z.length;V122)){if(!(al<65||ag>90)){af.push([Math.max(65,ag)|32,Math.min(al,90)|32])}if(!(al<97||ag>122)){af.push([Math.max(97,ag)&~32,Math.min(al,122)&~32])}}}}af.sort(function(av,au){return(av[0]-au[0])||(au[1]-av[1])});var ai=[];var ap=[NaN,NaN];for(var ar=0;arat[0]){if(at[1]+1>at[0]){an.push("-")}an.push(T(at[1]))}}an.push("]");return an.join("")}function W(al){var aj=al.source.match(new RegExp("(?:\\[(?:[^\\x5C\\x5D]|\\\\[\\s\\S])*\\]|\\\\u[A-Fa-f0-9]{4}|\\\\x[A-Fa-f0-9]{2}|\\\\[0-9]+|\\\\[^ux0-9]|\\(\\?[:!=]|[\\(\\)\\^]|[^\\x5B\\x5C\\(\\)\\^]+)","g"));var ah=aj.length;var an=[];for(var ak=0,am=0;ak=2&&ai==="["){aj[ak]=X(ag)}else{if(ai!=="\\"){aj[ak]=ag.replace(/[a-zA-Z]/g,function(ao){var ap=ao.charCodeAt(0);return"["+String.fromCharCode(ap&~32,ap|32)+"]"})}}}}return aj.join("")}var aa=[];for(var V=0,U=Z.length;V=0;){S[ac.charAt(ae)]=Y}}var af=Y[1];var aa=""+af;if(!ag.hasOwnProperty(aa)){ah.push(af);ag[aa]=null}}ah.push(/[\0-\uffff]/);V=k(ah)})();var X=T.length;var W=function(ah){var Z=ah.sourceCode,Y=ah.basePos;var ad=[Y,F];var af=0;var an=Z.match(V)||[];var aj={};for(var ae=0,aq=an.length;ae=5&&"lang-"===ap.substring(0,5);if(am&&!(ai&&typeof ai[1]==="string")){am=false;ap=J}if(!am){aj[ag]=ap}}var ab=af;af+=ag.length;if(!am){ad.push(Y+ab,ap)}else{var al=ai[1];var ak=ag.indexOf(al);var ac=ak+al.length;if(ai[2]){ac=ag.length-ai[2].length;ak=ac-al.length}var ar=ap.substring(5);B(Y+ab,ag.substring(0,ak),W,ad);B(Y+ab+ak,al,q(ar,al),ad);B(Y+ab+ac,ag.substring(ac),W,ad)}}ah.decorations=ad};return W}function i(T){var W=[],S=[];if(T.tripleQuotedStrings){W.push([C,/^(?:\'\'\'(?:[^\'\\]|\\[\s\S]|\'{1,2}(?=[^\']))*(?:\'\'\'|$)|\"\"\"(?:[^\"\\]|\\[\s\S]|\"{1,2}(?=[^\"]))*(?:\"\"\"|$)|\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$))/,null,"'\""])}else{if(T.multiLineStrings){W.push([C,/^(?:\'(?:[^\\\']|\\[\s\S])*(?:\'|$)|\"(?:[^\\\"]|\\[\s\S])*(?:\"|$)|\`(?:[^\\\`]|\\[\s\S])*(?:\`|$))/,null,"'\"`"])}else{W.push([C,/^(?:\'(?:[^\\\'\r\n]|\\.)*(?:\'|$)|\"(?:[^\\\"\r\n]|\\.)*(?:\"|$))/,null,"\"'"])}}if(T.verbatimStrings){S.push([C,/^@\"(?:[^\"]|\"\")*(?:\"|$)/,null])}var Y=T.hashComments;if(Y){if(T.cStyleComments){if(Y>1){W.push([j,/^#(?:##(?:[^#]|#(?!##))*(?:###|$)|.*)/,null,"#"])}else{W.push([j,/^#(?:(?:define|elif|else|endif|error|ifdef|include|ifndef|line|pragma|undef|warning)\b|[^\r\n]*)/,null,"#"])}S.push([C,/^<(?:(?:(?:\.\.\/)*|\/?)(?:[\w-]+(?:\/[\w-]+)+)?[\w-]+\.h|[a-z]\w*)>/,null])}else{W.push([j,/^#[^\r\n]*/,null,"#"])}}if(T.cStyleComments){S.push([j,/^\/\/[^\r\n]*/,null]);S.push([j,/^\/\*[\s\S]*?(?:\*\/|$)/,null])}if(T.regexLiterals){var X=("/(?=[^/*])(?:[^/\\x5B\\x5C]|\\x5C[\\s\\S]|\\x5B(?:[^\\x5C\\x5D]|\\x5C[\\s\\S])*(?:\\x5D|$))+/");S.push(["lang-regex",new RegExp("^"+M+"("+X+")")])}var V=T.types;if(V){S.push([O,V])}var U=(""+T.keywords).replace(/^ | $/g,"");if(U.length){S.push([z,new RegExp("^(?:"+U.replace(/[\s,]+/g,"|")+")\\b"),null])}W.push([F,/^\s+/,null," \r\n\t\xA0"]);S.push([G,/^@[a-z_$][a-z_$@0-9]*/i,null],[O,/^(?:[@_]?[A-Z]+[a-z][A-Za-z_$@0-9]*|\w+_t\b)/,null],[F,/^[a-z_$][a-z_$@0-9]*/i,null],[G,new RegExp("^(?:0x[a-f0-9]+|(?:\\d(?:_\\d+)*\\d*(?:\\.\\d*)?|\\.\\d\\+)(?:e[+\\-]?\\d+)?)[a-z]*","i"),null,"0123456789"],[F,/^\\[\s\S]?/,null],[L,/^.[^\s\w\.$@\'\"\`\/\#\\]*/,null]);return g(W,S)}var K=i({keywords:A,hashComments:true,cStyleComments:true,multiLineStrings:true,regexLiterals:true});function Q(V,ag){var U=/(?:^|\s)nocode(?:\s|$)/;var ab=/\r\n?|\n/;var ac=V.ownerDocument;var S;if(V.currentStyle){S=V.currentStyle.whiteSpace}else{if(window.getComputedStyle){S=ac.defaultView.getComputedStyle(V,null).getPropertyValue("white-space")}}var Z=S&&"pre"===S.substring(0,3);var af=ac.createElement("LI");while(V.firstChild){af.appendChild(V.firstChild)}var W=[af];function ae(al){switch(al.nodeType){case 1:if(U.test(al.className)){break}if("BR"===al.nodeName){ad(al);if(al.parentNode){al.parentNode.removeChild(al)}}else{for(var an=al.firstChild;an;an=an.nextSibling){ae(an)}}break;case 3:case 4:if(Z){var am=al.nodeValue;var aj=am.match(ab);if(aj){var ai=am.substring(0,aj.index);al.nodeValue=ai;var ah=am.substring(aj.index+aj[0].length);if(ah){var ak=al.parentNode;ak.insertBefore(ac.createTextNode(ah),al.nextSibling)}ad(al);if(!ai){al.parentNode.removeChild(al)}}}break}}function ad(ak){while(!ak.nextSibling){ak=ak.parentNode;if(!ak){return}}function ai(al,ar){var aq=ar?al.cloneNode(false):al;var ao=al.parentNode;if(ao){var ap=ai(ao,1);var an=al.nextSibling;ap.appendChild(aq);for(var am=an;am;am=an){an=am.nextSibling;ap.appendChild(am)}}return aq}var ah=ai(ak.nextSibling,0);for(var aj;(aj=ah.parentNode)&&aj.nodeType===1;){ah=aj}W.push(ah)}for(var Y=0;Y=S){ah+=2}if(V>=ap){Z+=2}}}var t={};function c(U,V){for(var S=V.length;--S>=0;){var T=V[S];if(!t.hasOwnProperty(T)){t[T]=U}else{if(window.console){console.warn("cannot override language handler %s",T)}}}}function q(T,S){if(!(T&&t.hasOwnProperty(T))){T=/^\s*]*(?:>|$)/],[j,/^<\!--[\s\S]*?(?:-\->|$)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],[L,/^(?:<[%?]|[%?]>)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i]]),["default-markup","htm","html","mxml","xhtml","xml","xsl"]);c(g([[F,/^[\s]+/,null," \t\r\n"],[n,/^(?:\"[^\"]*\"?|\'[^\']*\'?)/,null,"\"'"]],[[m,/^^<\/?[a-z](?:[\w.:-]*\w)?|\/?>$/i],[P,/^(?!style[\s=]|on)[a-z](?:[\w:-]*\w)?/i],["lang-uq.val",/^=\s*([^>\'\"\s]*(?:[^>\'\"\s\/]|\/(?=\s)))/],[L,/^[=<>\/]+/],["lang-js",/^on\w+\s*=\s*\"([^\"]+)\"/i],["lang-js",/^on\w+\s*=\s*\'([^\']+)\'/i],["lang-js",/^on\w+\s*=\s*([^\"\'>\s]+)/i],["lang-css",/^style\s*=\s*\"([^\"]+)\"/i],["lang-css",/^style\s*=\s*\'([^\']+)\'/i],["lang-css",/^style\s*=\s*([^\"\'>\s]+)/i]]),["in.tag"]);c(g([],[[n,/^[\s\S]+/]]),["uq.val"]);c(i({keywords:l,hashComments:true,cStyleComments:true,types:e}),["c","cc","cpp","cxx","cyc","m"]);c(i({keywords:"null,true,false"}),["json"]);c(i({keywords:R,hashComments:true,cStyleComments:true,verbatimStrings:true,types:e}),["cs"]);c(i({keywords:x,cStyleComments:true}),["java"]);c(i({keywords:H,hashComments:true,multiLineStrings:true}),["bsh","csh","sh"]);c(i({keywords:I,hashComments:true,multiLineStrings:true,tripleQuotedStrings:true}),["cv","py"]);c(i({keywords:s,hashComments:true,multiLineStrings:true,regexLiterals:true}),["perl","pl","pm"]);c(i({keywords:f,hashComments:true,multiLineStrings:true,regexLiterals:true}),["rb"]);c(i({keywords:w,cStyleComments:true,regexLiterals:true}),["js"]);c(i({keywords:r,hashComments:3,cStyleComments:true,multilineStrings:true,tripleQuotedStrings:true,regexLiterals:true}),["coffee"]);c(g([],[[C,/^[\s\S]+/]]),["regex"]);function d(V){var U=V.langExtension;try{var S=a(V.sourceNode);var T=S.sourceCode;V.sourceCode=T;V.spans=S.spans;V.basePos=0;q(U,T)(V);D(V)}catch(W){if("console" in window){console.log(W&&W.stack?W.stack:W)}}}function y(W,V,U){var S=document.createElement("PRE");S.innerHTML=W;if(U){Q(S,U)}var T={langExtension:V,numberLines:U,sourceNode:S};d(T);return S.innerHTML}function b(ad){function Y(af){return document.getElementsByTagName(af)}var ac=[Y("pre"),Y("code"),Y("xmp")];var T=[];for(var aa=0;aa=0){var ah=ai.match(ab);var am;if(!ah&&(am=o(aj))&&"CODE"===am.tagName){ah=am.className.match(ab)}if(ah){ah=ah[1]}var al=false;for(var ak=aj.parentNode;ak;ak=ak.parentNode){if((ak.tagName==="pre"||ak.tagName==="code"||ak.tagName==="xmp")&&ak.className&&ak.className.indexOf("prettyprint")>=0){al=true;break}}if(!al){var af=aj.className.match(/\blinenums\b(?::(\d+))?/);af=af?af[1]&&af[1].length?+af[1]:true:false;if(af){Q(aj,af)}S={langExtension:ah,sourceNode:aj,numberLines:af};d(S)}}}if(X]*(?:>|$)/],[PR.PR_COMMENT,/^<\!--[\s\S]*?(?:-\->|$)/],[PR.PR_PUNCTUATION,/^(?:<[%?]|[%?]>)/],["lang-",/^<\?([\s\S]+?)(?:\?>|$)/],["lang-",/^<%([\s\S]+?)(?:%>|$)/],["lang-",/^]*>([\s\S]+?)<\/xmp\b[^>]*>/i],["lang-handlebars",/^]*type\s*=\s*['"]?text\/x-handlebars-template['"]?\b[^>]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-js",/^]*>([\s\S]*?)(<\/script\b[^>]*>)/i],["lang-css",/^]*>([\s\S]*?)(<\/style\b[^>]*>)/i],["lang-in.tag",/^(<\/?[a-z][^<>]*>)/i],[PR.PR_DECLARATION,/^{{[#^>/]?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{&?\s*[\w.][^}]*}}/],[PR.PR_DECLARATION,/^{{{>?\s*[\w.][^}]*}}}/],[PR.PR_COMMENT,/^{{![^}]*}}/]]),["handlebars","hbs"]);PR.registerLangHandler(PR.createSimpleLexer([[PR.PR_PLAIN,/^[ \t\r\n\f]+/,null," \t\r\n\f"]],[[PR.PR_STRING,/^\"(?:[^\n\r\f\\\"]|\\(?:\r\n?|\n|\f)|\\[\s\S])*\"/,null],[PR.PR_STRING,/^\'(?:[^\n\r\f\\\']|\\(?:\r\n?|\n|\f)|\\[\s\S])*\'/,null],["lang-css-str",/^url\(([^\)\"\']*)\)/i],[PR.PR_KEYWORD,/^(?:url|rgb|\!important|@import|@page|@media|@charset|inherit)(?=[^\-\w]|$)/i,null],["lang-css-kw",/^(-?(?:[_a-z]|(?:\\[0-9a-f]+ ?))(?:[_a-z0-9\-]|\\(?:\\[0-9a-f]+ ?))*)\s*:/i],[PR.PR_COMMENT,/^\/\*[^*]*\*+(?:[^\/*][^*]*\*+)*\//],[PR.PR_COMMENT,/^(?:)/],[PR.PR_LITERAL,/^(?:\d+|\d*\.\d+)(?:%|[a-z]+)?/i],[PR.PR_LITERAL,/^#(?:[0-9a-f]{3}){1,2}/i],[PR.PR_PLAIN,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i],[PR.PR_PUNCTUATION,/^[^\s\w\'\"]+/]]),["css"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_KEYWORD,/^-?(?:[_a-z]|(?:\\[\da-f]+ ?))(?:[_a-z\d\-]|\\(?:\\[\da-f]+ ?))*/i]]),["css-kw"]);PR.registerLangHandler(PR.createSimpleLexer([],[[PR.PR_STRING,/^[^\)\"\']+/]]),["css-str"]); diff --git a/packages/runtime/tests/coverage/lcov-report/query-processor.ts.html b/packages/runtime/tests/coverage/lcov-report/query-processor.ts.html deleted file mode 100644 index c50ed09a5..000000000 --- a/packages/runtime/tests/coverage/lcov-report/query-processor.ts.html +++ /dev/null @@ -1,247 +0,0 @@ - - - - - - Code coverage report for query-processor.ts - - - - - - - - - -
    -
    -

    All files query-processor.ts

    -
    - -
    - 88.88% - Statements - 48/54 -
    - - -
    - 92.85% - Branches - 13/14 -
    - - -
    - 66.66% - Functions - 2/3 -
    - - -
    - 88.88% - Lines - 48/54 -
    - - -
    -

    - Press n or j to go to the next uncovered block, b, p or k for the previous block. -

    - -
    -
    -
    
    -
    1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -551x -1x -1x -1x -1x -1x -1x -12x -12x -12x -12x -12x -12x -12x -12x -12x -9x -12x -3x -3x -3x -3x -12x -12x -12x -6x -6x -6x -8x -8x -4x -4x -4x -4x -4x -4x -4x -4x -4x -4x -8x -6x -12x -12x -12x -1x -1x -  -  -  -  -  -  -1x - 
    import deepcopy from 'deepcopy';
    -import { PolicyOperationKind, QueryContext, Service } from '../../types';
    - 
    -export class QueryProcessor {
    -    constructor(private readonly service: Service) {}
    - 
    -    async processQueryArgs(
    -        model: string,
    -        args: any,
    -        operation: PolicyOperationKind,
    -        context: QueryContext
    -    ) {
    -        const r = args ? deepcopy(args) : {};
    -        const guard = this.service.buildQueryGuard(model, operation, context);
    -        if (guard) {
    -            if (!r.where) {
    -                r.where = guard;
    -            } else {
    -                r.where = {
    -                    AND: [guard, r.where],
    -                };
    -            }
    -        }
    - 
    -        if (r.include || r.select) {
    -            // "include" and "select" are mutually exclusive
    -            const selector = r.include ? 'include' : 'select';
    -            for (const [field, value] of Object.entries(r[selector])) {
    -                const fieldInfo = await this.service.resolveField(model, field);
    -                if (fieldInfo && fieldInfo.isArray) {
    -                    // note that Prisma only allows to attach filter for "to-many" relation
    -                    // query, so we need to handle "to-one" filter separately in post-processing
    -                    const fieldGuard = await this.processQueryArgs(
    -                        fieldInfo.type,
    -                        value === true ? {} : value,
    -                        operation,
    -                        context
    -                    );
    -                    r[selector][field] = fieldGuard;
    -                }
    -            }
    -        }
    - 
    -        return r;
    -    }
    - 
    -    async postProcess(
    -        model: string,
    -        queryArgs: any,
    -        data: any,
    -        operation: PolicyOperationKind,
    -        context: QueryContext
    -    ) {}
    -}
    - 
    - -
    -
    - - - - - - - - \ No newline at end of file diff --git a/packages/runtime/tests/coverage/lcov-report/sort-arrow-sprite.png b/packages/runtime/tests/coverage/lcov-report/sort-arrow-sprite.png deleted file mode 100644 index 6ed68316eb3f65dec9063332d2f69bf3093bbfab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^>_9Bd!3HEZxJ@+%Qh}Z>jv*C{$p!i!8j}?a+@3A= zIAGwzjijN=FBi!|L1t?LM;Q;gkwn>2cAy-KV{dn nf0J1DIvEHQu*n~6U}x}qyky7vi4|9XhBJ7&`njxgN@xNA8m%nc diff --git a/packages/runtime/tests/coverage/lcov-report/sorter.js b/packages/runtime/tests/coverage/lcov-report/sorter.js deleted file mode 100644 index 2bb296a8c..000000000 --- a/packages/runtime/tests/coverage/lcov-report/sorter.js +++ /dev/null @@ -1,196 +0,0 @@ -/* eslint-disable */ -var addSorting = (function() { - 'use strict'; - var cols, - currentSort = { - index: 0, - desc: false - }; - - // returns the summary table element - function getTable() { - return document.querySelector('.coverage-summary'); - } - // returns the thead element of the summary table - function getTableHeader() { - return getTable().querySelector('thead tr'); - } - // returns the tbody element of the summary table - function getTableBody() { - return getTable().querySelector('tbody'); - } - // returns the th element for nth column - function getNthColumn(n) { - return getTableHeader().querySelectorAll('th')[n]; - } - - function onFilterInput() { - const searchValue = document.getElementById('fileSearch').value; - const rows = document.getElementsByTagName('tbody')[0].children; - for (let i = 0; i < rows.length; i++) { - const row = rows[i]; - if ( - row.textContent - .toLowerCase() - .includes(searchValue.toLowerCase()) - ) { - row.style.display = ''; - } else { - row.style.display = 'none'; - } - } - } - - // loads the search box - function addSearchBox() { - var template = document.getElementById('filterTemplate'); - var templateClone = template.content.cloneNode(true); - templateClone.getElementById('fileSearch').oninput = onFilterInput; - template.parentElement.appendChild(templateClone); - } - - // loads all columns - function loadColumns() { - var colNodes = getTableHeader().querySelectorAll('th'), - colNode, - cols = [], - col, - i; - - for (i = 0; i < colNodes.length; i += 1) { - colNode = colNodes[i]; - col = { - key: colNode.getAttribute('data-col'), - sortable: !colNode.getAttribute('data-nosort'), - type: colNode.getAttribute('data-type') || 'string' - }; - cols.push(col); - if (col.sortable) { - col.defaultDescSort = col.type === 'number'; - colNode.innerHTML = - colNode.innerHTML + ''; - } - } - return cols; - } - // attaches a data attribute to every tr element with an object - // of data values keyed by column name - function loadRowData(tableRow) { - var tableCols = tableRow.querySelectorAll('td'), - colNode, - col, - data = {}, - i, - val; - for (i = 0; i < tableCols.length; i += 1) { - colNode = tableCols[i]; - col = cols[i]; - val = colNode.getAttribute('data-value'); - if (col.type === 'number') { - val = Number(val); - } - data[col.key] = val; - } - return data; - } - // loads all row data - function loadData() { - var rows = getTableBody().querySelectorAll('tr'), - i; - - for (i = 0; i < rows.length; i += 1) { - rows[i].data = loadRowData(rows[i]); - } - } - // sorts the table using the data for the ith column - function sortByIndex(index, desc) { - var key = cols[index].key, - sorter = function(a, b) { - a = a.data[key]; - b = b.data[key]; - return a < b ? -1 : a > b ? 1 : 0; - }, - finalSorter = sorter, - tableBody = document.querySelector('.coverage-summary tbody'), - rowNodes = tableBody.querySelectorAll('tr'), - rows = [], - i; - - if (desc) { - finalSorter = function(a, b) { - return -1 * sorter(a, b); - }; - } - - for (i = 0; i < rowNodes.length; i += 1) { - rows.push(rowNodes[i]); - tableBody.removeChild(rowNodes[i]); - } - - rows.sort(finalSorter); - - for (i = 0; i < rows.length; i += 1) { - tableBody.appendChild(rows[i]); - } - } - // removes sort indicators for current column being sorted - function removeSortIndicators() { - var col = getNthColumn(currentSort.index), - cls = col.className; - - cls = cls.replace(/ sorted$/, '').replace(/ sorted-desc$/, ''); - col.className = cls; - } - // adds sort indicators for current column being sorted - function addSortIndicators() { - getNthColumn(currentSort.index).className += currentSort.desc - ? ' sorted-desc' - : ' sorted'; - } - // adds event listeners for all sorter widgets - function enableUI() { - var i, - el, - ithSorter = function ithSorter(i) { - var col = cols[i]; - - return function() { - var desc = col.defaultDescSort; - - if (currentSort.index === i) { - desc = !currentSort.desc; - } - sortByIndex(i, desc); - removeSortIndicators(); - currentSort.index = i; - currentSort.desc = desc; - addSortIndicators(); - }; - }; - for (i = 0; i < cols.length; i += 1) { - if (cols[i].sortable) { - // add the click event handler on the th so users - // dont have to click on those tiny arrows - el = getNthColumn(i).querySelector('.sorter').parentElement; - if (el.addEventListener) { - el.addEventListener('click', ithSorter(i)); - } else { - el.attachEvent('onclick', ithSorter(i)); - } - } - } - } - // adds sorting functionality to the UI - return function() { - if (!getTable()) { - return; - } - cols = loadColumns(); - loadData(); - addSearchBox(); - addSortIndicators(); - enableUI(); - }; -})(); - -window.addEventListener('load', addSorting); diff --git a/packages/runtime/tests/coverage/lcov.info b/packages/runtime/tests/coverage/lcov.info deleted file mode 100644 index 4eb00d717..000000000 --- a/packages/runtime/tests/coverage/lcov.info +++ /dev/null @@ -1,83 +0,0 @@ -TN: -SF:src/handler/data/query-processor.ts -FN:5,QueryProcessor -FN:7,processQueryArgs -FN:47,postProcess -FNF:3 -FNH:2 -FNDA:1,QueryProcessor -FNDA:12,processQueryArgs -FNDA:0,postProcess -DA:1,1 -DA:2,1 -DA:3,1 -DA:4,1 -DA:5,1 -DA:6,1 -DA:7,1 -DA:8,12 -DA:9,12 -DA:10,12 -DA:11,12 -DA:12,12 -DA:13,12 -DA:14,12 -DA:15,12 -DA:16,12 -DA:17,9 -DA:18,12 -DA:19,3 -DA:20,3 -DA:21,3 -DA:22,3 -DA:23,12 -DA:24,12 -DA:25,12 -DA:26,6 -DA:27,6 -DA:28,6 -DA:29,8 -DA:30,8 -DA:31,4 -DA:32,4 -DA:33,4 -DA:34,4 -DA:35,4 -DA:36,4 -DA:37,4 -DA:38,4 -DA:39,4 -DA:40,4 -DA:41,8 -DA:42,6 -DA:43,12 -DA:44,12 -DA:45,12 -DA:46,1 -DA:47,1 -DA:48,0 -DA:49,0 -DA:50,0 -DA:51,0 -DA:52,0 -DA:53,0 -DA:54,1 -LF:54 -LH:48 -BRDA:5,0,0,1 -BRDA:7,1,0,12 -BRDA:13,2,0,0 -BRDA:16,3,0,9 -BRDA:18,4,0,3 -BRDA:25,5,0,9 -BRDA:25,6,0,6 -BRDA:27,7,0,3 -BRDA:27,8,0,3 -BRDA:28,9,0,8 -BRDA:30,10,0,6 -BRDA:30,11,0,4 -BRDA:35,12,0,2 -BRDA:35,13,0,2 -BRF:14 -BRH:13 -end_of_record diff --git a/packages/runtime/tests/query-processor.test.ts b/packages/runtime/tests/query-processor.test.ts index 1bdc61709..40ac78a1a 100644 --- a/packages/runtime/tests/query-processor.test.ts +++ b/packages/runtime/tests/query-processor.test.ts @@ -158,13 +158,15 @@ describe('Query Processor Tests', () => { ); expect(r).toEqual(expect.objectContaining({ include: { list: true } })); - // select to-one, no processing + // select to-one, "id" is injected r = await processor.processQueryArgs( 'Todo', { select: { list: true } }, 'read', {} ); - expect(r).toEqual(expect.objectContaining({ select: { list: true } })); + expect(r).toEqual( + expect.objectContaining({ select: { id: true, list: true } }) + ); }); }); diff --git a/packages/schema/src/generator/server/data/expression-writer.ts b/packages/schema/src/generator/prisma/expression-writer.ts similarity index 99% rename from packages/schema/src/generator/server/data/expression-writer.ts rename to packages/schema/src/generator/prisma/expression-writer.ts index cb2fd4586..5ca7ccfc2 100644 --- a/packages/schema/src/generator/server/data/expression-writer.ts +++ b/packages/schema/src/generator/prisma/expression-writer.ts @@ -13,7 +13,7 @@ import { UnaryExpr, } from '@lang/generated/ast'; import { CodeBlockWriter } from 'ts-morph'; -import { GeneratorError } from '../../types'; +import { GeneratorError } from '../types'; import { TypedNode } from '@lang/types'; import PlainExpressionBuilder from './plain-expression-builder'; diff --git a/packages/schema/src/generator/prisma/index.ts b/packages/schema/src/generator/prisma/index.ts index 09f7eaab6..8a543096c 100644 --- a/packages/schema/src/generator/prisma/index.ts +++ b/packages/schema/src/generator/prisma/index.ts @@ -1,102 +1,23 @@ -import { writeFile } from 'fs/promises'; -import { AstNode } from 'langium'; -import path from 'path'; import colors from 'colors'; -import { - AttributeArg, - DataModel, - DataModelAttribute, - DataModelField, - DataModelFieldAttribute, - DataSource, - Enum, - Expression, - InvocationExpr, - isArrayExpr, - isDataModel, - isEnum, - isInvocationExpr, - isLiteralExpr, - isReferenceExpr, - LiteralExpr, -} from '@lang/generated/ast'; -import { Context, Generator, GeneratorError } from '../types'; -import { - AttributeArg as PrismaAttributeArg, - AttributeArgValue as PrismaAttributeArgValue, - DataSourceUrl as PrismaDataSourceUrl, - FieldAttribute as PrismaFieldAttribute, - ModelAttribute as PrismaModelAttribute, - Model as PrismaDataModel, - FieldReference as PrismaFieldReference, - FieldReferenceArg as PrismaFieldReferenceArg, - FunctionCall as PrismaFunctionCall, - FunctionCallArg as PrismaFunctionCallArg, - PrismaModel, - ModelFieldType, -} from './prisma-builder'; +import { Context, Generator } from '../types'; import { execSync } from 'child_process'; -import { Project, SourceFile, VariableDeclarationKind } from 'ts-morph'; -import { GUARD_FIELD_NAME, RUNTIME_PACKAGE } from '../constants'; -import type { PolicyKind, PolicyOperationKind } from '@zenstackhq/runtime'; -import ExpressionWriter from '../server/data/expression-writer'; - -const supportedProviders = ['postgresql', 'mysql', 'sqlite', 'sqlserver']; -const supportedAttrbutes = [ - 'id', - 'index', - 'relation', - 'default', - 'createdAt', - 'updatedAt', - 'unique', -]; +import PrismaSchemaGenerator from './schema-generator'; +import QueryGuardGenerator from './query-gard-generator'; export default class PrismaGenerator implements Generator { async generate(context: Context) { // generate prisma schema - const schemaFile = await this.generateSchema(context); + const schemaFile = await new PrismaSchemaGenerator(context).generate(); // run prisma generate and install @prisma/client await this.generatePrismaClient(schemaFile); // generate prisma query guard - await this.generateQueryGuard(context); + await new QueryGuardGenerator(context).generate(); console.log(colors.blue(` ✔️ Prisma schema and query code generated`)); } - private async generateSchema(context: Context) { - const { schema } = context; - const prisma = new PrismaModel(); - - for (const decl of schema.declarations) { - switch (decl.$type) { - case DataSource: - this.generateDataSource( - context, - prisma, - decl as DataSource - ); - break; - - case Enum: - this.generateEnum(context, prisma, decl as Enum); - break; - - case DataModel: - this.generateModel(context, prisma, decl as DataModel); - break; - } - } - - this.generateGenerator(context, prisma); - - const outFile = path.join(context.outDir, 'schema.prisma'); - await writeFile(outFile, prisma.toString()); - return outFile; - } - async generatePrismaClient(schemaFile: string) { try { execSync('npx prisma -v'); @@ -107,423 +28,4 @@ export default class PrismaGenerator implements Generator { execSync(`npx prisma generate --schema "${schemaFile}"`); } - - private isStringLiteral(node: AstNode): node is LiteralExpr { - return isLiteralExpr(node) && typeof node.value === 'string'; - } - - private generateDataSource( - context: Context, - prisma: PrismaModel, - dataSource: DataSource - ) { - let provider: string | undefined = undefined; - let url: PrismaDataSourceUrl | undefined = undefined; - let shadowDatabaseUrl: PrismaDataSourceUrl | undefined = undefined; - - for (const f of dataSource.fields) { - switch (f.name) { - case 'provider': { - if (this.isStringLiteral(f.value)) { - provider = f.value.value as string; - } else { - throw new GeneratorError( - 'Datasource provider must be set to a string' - ); - } - if (!supportedProviders.includes(provider)) { - throw new GeneratorError( - `Provider ${provider} is not supported. Supported providers: ${supportedProviders.join( - ', ' - )}` - ); - } - break; - } - - case 'url': { - const r = this.extractDataSourceUrl(f.value); - if (!r) { - throw new GeneratorError( - 'Invalid value for datasource url' - ); - } - url = r; - break; - } - - case 'shadowDatabaseUrl': { - const r = this.extractDataSourceUrl(f.value); - if (!r) { - throw new GeneratorError( - 'Invalid value for datasource url' - ); - } - shadowDatabaseUrl = r; - break; - } - } - } - - if (!provider) { - throw new GeneratorError('Datasource is missing "provider" field'); - } - if (!url) { - throw new GeneratorError('Datasource is missing "url" field'); - } - - prisma.addDataSource(dataSource.name, provider, url, shadowDatabaseUrl); - } - - private extractDataSourceUrl(fieldValue: LiteralExpr | InvocationExpr) { - if (this.isStringLiteral(fieldValue)) { - return new PrismaDataSourceUrl(fieldValue.value as string, false); - } else if ( - isInvocationExpr(fieldValue) && - fieldValue.function.ref?.name === 'env' && - fieldValue.args.length === 1 && - this.isStringLiteral(fieldValue.args[0].value) - ) { - return new PrismaDataSourceUrl( - fieldValue.args[0].value.value as string, - true - ); - } else { - return null; - } - } - - private generateGenerator(context: Context, prisma: PrismaModel) { - prisma.addGenerator( - 'client', - 'prisma-client-js', - path.join(context.outDir, '.prisma'), - ['fieldReference'] - ); - } - - private generateModel( - context: Context, - prisma: PrismaModel, - decl: DataModel - ) { - const model = prisma.addModel(decl.name); - for (const field of decl.fields) { - this.generateModelField(model, field); - } - - // add an "zenstack_guard" field for dealing with pure auth() related conditions - model.addField(GUARD_FIELD_NAME, 'Boolean', [ - new PrismaFieldAttribute('default', [ - new PrismaAttributeArg( - undefined, - new PrismaAttributeArgValue('Boolean', true) - ), - ]), - ]); - - for (const attr of decl.attributes.filter((attr) => - supportedAttrbutes.includes(attr.decl.ref?.name!) - )) { - this.generateModelAttribute(model, attr); - } - } - - private generateModelField(model: PrismaDataModel, field: DataModelField) { - const type = new ModelFieldType( - (field.type.type || field.type.reference?.ref?.name)!, - field.type.array, - field.type.optional - ); - - const attributes = field.attributes - .filter((attr) => supportedAttrbutes.includes(attr.decl.ref?.name!)) - .map((attr) => this.makeFieldAttribute(attr)); - model.addField(field.name, type, attributes); - } - - private makeFieldAttribute(attr: DataModelFieldAttribute) { - return new PrismaFieldAttribute( - attr.decl.ref?.name!, - attr.args.map((arg) => this.makeAttributeArg(arg)) - ); - } - - makeAttributeArg(arg: AttributeArg): PrismaAttributeArg { - return new PrismaAttributeArg( - arg.name, - this.makeAttributeArgValue(arg.value) - ); - } - - makeAttributeArgValue(node: Expression): PrismaAttributeArgValue { - if (isLiteralExpr(node)) { - switch (typeof node.value) { - case 'string': - return new PrismaAttributeArgValue('String', node.value); - case 'number': - return new PrismaAttributeArgValue('Number', node.value); - case 'boolean': - return new PrismaAttributeArgValue('Boolean', node.value); - default: - throw new GeneratorError( - `Unexpected literal type: ${typeof node.value}` - ); - } - } else if (isArrayExpr(node)) { - return new PrismaAttributeArgValue( - 'Array', - new Array( - ...node.items.map((item) => - this.makeAttributeArgValue(item) - ) - ) - ); - } else if (isReferenceExpr(node)) { - return new PrismaAttributeArgValue( - 'FieldReference', - new PrismaFieldReference( - node.target.ref?.name!, - node.args.map( - (arg) => - new PrismaFieldReferenceArg(arg.name, arg.value) - ) - ) - ); - } else if (isInvocationExpr(node)) { - // invocation - return new PrismaAttributeArgValue( - 'FunctionCall', - this.makeFunctionCall(node) - ); - } else { - throw new GeneratorError( - `Unsupported attribute argument expression type: ${node.$type}` - ); - } - } - - makeFunctionCall(node: InvocationExpr): PrismaFunctionCall { - return new PrismaFunctionCall( - node.function.ref?.name!, - node.args.map((arg) => { - if (!isLiteralExpr(arg.value)) { - throw new GeneratorError( - 'Function call argument must be literal' - ); - } - return new PrismaFunctionCallArg(arg.name, arg.value.value); - }) - ); - } - - private generateModelAttribute( - model: PrismaDataModel, - attr: DataModelAttribute - ) { - model.attributes.push( - new PrismaModelAttribute( - attr.decl.ref?.name!, - attr.args.map((arg) => this.makeAttributeArg(arg)) - ) - ); - } - - private generateEnum(context: Context, prisma: PrismaModel, decl: Enum) { - prisma.addEnum( - decl.name, - decl.fields.map((f) => f.name) - ); - } - - private async generateQueryGuard(context: Context) { - const project = new Project(); - const sf = project.createSourceFile( - path.join(context.outDir, 'query/guard.ts'), - undefined, - { overwrite: true } - ); - - sf.addImportDeclaration({ - namedImports: [{ name: 'QueryContext' }], - moduleSpecifier: RUNTIME_PACKAGE, - isTypeOnly: true, - }); - - // import enums - for (const e of context.schema.declarations.filter((d) => isEnum(d))) { - sf.addImportDeclaration({ - namedImports: [{ name: e.name }], - moduleSpecifier: '../.prisma', - }); - } - - // const models = extractDataModelsWithAllowRules(context.schema); - const models = context.schema.declarations.filter((d) => - isDataModel(d) - ) as DataModel[]; - - this.generateFieldMapping(models, sf); - - models.forEach((model) => this.generateQueryGuardForModel(model, sf)); - - sf.formatText({}); - await project.save(); - } - - private generateFieldMapping(models: DataModel[], sourceFile: SourceFile) { - const mapping = Object.fromEntries( - models.map((m) => [ - m.name, - Object.fromEntries( - m.fields - .filter((f) => isDataModel(f.type.reference?.ref)) - .map((f) => [ - f.name, - { - type: f.type.reference!.ref!.name, - isArray: f.type.array, - }, - ]) - ), - ]) - ); - - sourceFile.addVariableStatement({ - isExported: true, - declarationKind: VariableDeclarationKind.Const, - declarations: [ - { - name: '_fieldMapping', - initializer: JSON.stringify(mapping), - }, - ], - }); - } - - private getPolicyExpressions( - model: DataModel, - kind: PolicyKind, - operation: PolicyOperationKind - ) { - const attrs = model.attributes.filter( - (attr) => attr.decl.ref?.name === kind - ); - return attrs - .filter((attr) => { - if ( - !isLiteralExpr(attr.args[0].value) || - typeof attr.args[0].value.value !== 'string' - ) { - return false; - } - const ops = attr.args[0].value.value - .split(',') - .map((s) => s.trim()); - return ops.includes(operation) || ops.includes('all'); - }) - .map((attr) => attr.args[1].value); - } - - private async generateQueryGuardForModel( - model: DataModel, - sourceFile: SourceFile - ) { - for (const kind of ['create', 'update', 'read', 'delete']) { - const func = sourceFile - .addFunction({ - name: model.name + '_' + kind, - returnType: 'any', - parameters: [ - { - name: 'context', - type: 'QueryContext', - }, - ], - isExported: true, - }) - .addBody(); - - func.addStatements('const { user } = context;'); - - // r = ; - func.addVariableStatement({ - declarationKind: VariableDeclarationKind.Const, - declarations: [ - { - name: 'r', - initializer: (writer) => { - const exprWriter = new ExpressionWriter(writer); - const denies = this.getPolicyExpressions( - model, - 'deny', - kind as PolicyOperationKind - ); - const allows = this.getPolicyExpressions( - model, - 'allow', - kind as PolicyOperationKind - ); - - const writeDenies = () => { - writer.conditionalWrite( - denies.length > 1, - '{ AND: [' - ); - denies.forEach((expr, i) => { - writer.block(() => { - writer.write('NOT: '); - exprWriter.write(expr); - }); - writer.conditionalWrite( - i !== denies.length - 1, - ',' - ); - }); - writer.conditionalWrite( - denies.length > 1, - ']}' - ); - }; - - const writeAllows = () => { - writer.conditionalWrite( - allows.length > 1, - '{ OR: [' - ); - allows.forEach((expr, i) => { - exprWriter.write(expr); - writer.conditionalWrite( - i !== allows.length - 1, - ',' - ); - }); - writer.conditionalWrite( - allows.length > 1, - ']}' - ); - }; - - if (allows.length > 0 && denies.length > 0) { - writer.writeLine('{ AND: ['); - writeDenies(); - writer.writeLine(','); - writeAllows(); - writer.writeLine(']}'); - } else if (denies.length > 0) { - writeDenies(); - } else if (allows.length > 0) { - writeAllows(); - } else { - // disallow any operation - writer.write(`{ ${GUARD_FIELD_NAME}: false }`); - } - }, - }, - ], - }); - - func.addStatements('return r;'); - } - } } diff --git a/packages/schema/src/generator/server/data/plain-expression-builder.ts b/packages/schema/src/generator/prisma/plain-expression-builder.ts similarity index 98% rename from packages/schema/src/generator/server/data/plain-expression-builder.ts rename to packages/schema/src/generator/prisma/plain-expression-builder.ts index f6cd5ee60..0d7db3573 100644 --- a/packages/schema/src/generator/server/data/plain-expression-builder.ts +++ b/packages/schema/src/generator/prisma/plain-expression-builder.ts @@ -1,4 +1,4 @@ -import { GeneratorError } from '../../types'; +import { GeneratorError } from '../types'; import { ArrayExpr, Expression, diff --git a/packages/schema/src/generator/prisma/query-gard-generator.ts b/packages/schema/src/generator/prisma/query-gard-generator.ts new file mode 100644 index 000000000..f1bc42366 --- /dev/null +++ b/packages/schema/src/generator/prisma/query-gard-generator.ts @@ -0,0 +1,208 @@ +import { + DataModel, + isDataModel, + isEnum, + isLiteralExpr, +} from '@lang/generated/ast'; +import { PolicyKind, PolicyOperationKind } from '@zenstackhq/runtime'; +import path from 'path'; +import { Project, SourceFile, VariableDeclarationKind } from 'ts-morph'; +import { GUARD_FIELD_NAME, RUNTIME_PACKAGE } from '../constants'; +import { Context } from '../types'; +import ExpressionWriter from './expression-writer'; + +export default class QueryGuardGenerator { + constructor(private readonly context: Context) {} + + async generate() { + const project = new Project(); + const sf = project.createSourceFile( + path.join(this.context.outDir, 'query/guard.ts'), + undefined, + { overwrite: true } + ); + + sf.addImportDeclaration({ + namedImports: [{ name: 'QueryContext' }], + moduleSpecifier: RUNTIME_PACKAGE, + isTypeOnly: true, + }); + + // import enums + for (const e of this.context.schema.declarations.filter((d) => + isEnum(d) + )) { + sf.addImportDeclaration({ + namedImports: [{ name: e.name }], + moduleSpecifier: '../.prisma', + }); + } + + const models = this.context.schema.declarations.filter((d) => + isDataModel(d) + ) as DataModel[]; + + this.generateFieldMapping(models, sf); + + models.forEach((model) => this.generateQueryGuardForModel(model, sf)); + + sf.formatText({}); + await project.save(); + } + + private generateFieldMapping(models: DataModel[], sourceFile: SourceFile) { + const mapping = Object.fromEntries( + models.map((m) => [ + m.name, + Object.fromEntries( + m.fields + .filter((f) => isDataModel(f.type.reference?.ref)) + .map((f) => [ + f.name, + { + type: f.type.reference!.ref!.name, + isArray: f.type.array, + }, + ]) + ), + ]) + ); + + sourceFile.addVariableStatement({ + isExported: true, + declarationKind: VariableDeclarationKind.Const, + declarations: [ + { + name: '_fieldMapping', + initializer: JSON.stringify(mapping), + }, + ], + }); + } + + private getPolicyExpressions( + model: DataModel, + kind: PolicyKind, + operation: PolicyOperationKind + ) { + const attrs = model.attributes.filter( + (attr) => attr.decl.ref?.name === kind + ); + return attrs + .filter((attr) => { + if ( + !isLiteralExpr(attr.args[0].value) || + typeof attr.args[0].value.value !== 'string' + ) { + return false; + } + const ops = attr.args[0].value.value + .split(',') + .map((s) => s.trim()); + return ops.includes(operation) || ops.includes('all'); + }) + .map((attr) => attr.args[1].value); + } + + private async generateQueryGuardForModel( + model: DataModel, + sourceFile: SourceFile + ) { + for (const kind of ['create', 'update', 'read', 'delete']) { + const func = sourceFile + .addFunction({ + name: model.name + '_' + kind, + returnType: 'any', + parameters: [ + { + name: 'context', + type: 'QueryContext', + }, + ], + isExported: true, + }) + .addBody(); + + func.addStatements('const { user } = context;'); + + // r = ; + func.addVariableStatement({ + declarationKind: VariableDeclarationKind.Const, + declarations: [ + { + name: 'r', + initializer: (writer) => { + const exprWriter = new ExpressionWriter(writer); + const denies = this.getPolicyExpressions( + model, + 'deny', + kind as PolicyOperationKind + ); + const allows = this.getPolicyExpressions( + model, + 'allow', + kind as PolicyOperationKind + ); + + const writeDenies = () => { + writer.conditionalWrite( + denies.length > 1, + '{ AND: [' + ); + denies.forEach((expr, i) => { + writer.block(() => { + writer.write('NOT: '); + exprWriter.write(expr); + }); + writer.conditionalWrite( + i !== denies.length - 1, + ',' + ); + }); + writer.conditionalWrite( + denies.length > 1, + ']}' + ); + }; + + const writeAllows = () => { + writer.conditionalWrite( + allows.length > 1, + '{ OR: [' + ); + allows.forEach((expr, i) => { + exprWriter.write(expr); + writer.conditionalWrite( + i !== allows.length - 1, + ',' + ); + }); + writer.conditionalWrite( + allows.length > 1, + ']}' + ); + }; + + if (allows.length > 0 && denies.length > 0) { + writer.writeLine('{ AND: ['); + writeDenies(); + writer.writeLine(','); + writeAllows(); + writer.writeLine(']}'); + } else if (denies.length > 0) { + writeDenies(); + } else if (allows.length > 0) { + writeAllows(); + } else { + // disallow any operation + writer.write(`{ ${GUARD_FIELD_NAME}: false }`); + } + }, + }, + ], + }); + + func.addStatements('return r;'); + } + } +} diff --git a/packages/schema/src/generator/prisma/schema-generator.ts b/packages/schema/src/generator/prisma/schema-generator.ts new file mode 100644 index 000000000..e0a267284 --- /dev/null +++ b/packages/schema/src/generator/prisma/schema-generator.ts @@ -0,0 +1,297 @@ +import { + AttributeArg, + DataModel, + DataModelAttribute, + DataModelField, + DataModelFieldAttribute, + DataSource, + Enum, + Expression, + InvocationExpr, + isArrayExpr, + isInvocationExpr, + isLiteralExpr, + isReferenceExpr, + LiteralExpr, +} from '@lang/generated/ast'; +import { writeFile } from 'fs/promises'; +import { AstNode } from 'langium'; +import path from 'path'; +import { GUARD_FIELD_NAME } from '../constants'; +import { Context, GeneratorError } from '../types'; +import { + AttributeArg as PrismaAttributeArg, + AttributeArgValue as PrismaAttributeArgValue, + DataSourceUrl as PrismaDataSourceUrl, + FieldAttribute as PrismaFieldAttribute, + ModelAttribute as PrismaModelAttribute, + Model as PrismaDataModel, + FieldReference as PrismaFieldReference, + FieldReferenceArg as PrismaFieldReferenceArg, + FunctionCall as PrismaFunctionCall, + FunctionCallArg as PrismaFunctionCallArg, + PrismaModel, + ModelFieldType, +} from './prisma-builder'; + +const supportedProviders = ['postgresql', 'mysql', 'sqlite', 'sqlserver']; +const supportedAttrbutes = [ + 'id', + 'index', + 'relation', + 'default', + 'createdAt', + 'updatedAt', + 'unique', +]; + +export default class PrismaSchemaGenerator { + constructor(private readonly context: Context) {} + + async generate() { + const { schema } = this.context; + const prisma = new PrismaModel(); + + for (const decl of schema.declarations) { + switch (decl.$type) { + case DataSource: + this.generateDataSource(prisma, decl as DataSource); + break; + + case Enum: + this.generateEnum(prisma, decl as Enum); + break; + + case DataModel: + this.generateModel(prisma, decl as DataModel); + break; + } + } + + this.generateGenerator(prisma); + + const outFile = path.join(this.context.outDir, 'schema.prisma'); + await writeFile(outFile, prisma.toString()); + return outFile; + } + + private generateDataSource(prisma: PrismaModel, dataSource: DataSource) { + let provider: string | undefined = undefined; + let url: PrismaDataSourceUrl | undefined = undefined; + let shadowDatabaseUrl: PrismaDataSourceUrl | undefined = undefined; + + for (const f of dataSource.fields) { + switch (f.name) { + case 'provider': { + if (this.isStringLiteral(f.value)) { + provider = f.value.value as string; + } else { + throw new GeneratorError( + 'Datasource provider must be set to a string' + ); + } + if (!supportedProviders.includes(provider)) { + throw new GeneratorError( + `Provider ${provider} is not supported. Supported providers: ${supportedProviders.join( + ', ' + )}` + ); + } + break; + } + + case 'url': { + const r = this.extractDataSourceUrl(f.value); + if (!r) { + throw new GeneratorError( + 'Invalid value for datasource url' + ); + } + url = r; + break; + } + + case 'shadowDatabaseUrl': { + const r = this.extractDataSourceUrl(f.value); + if (!r) { + throw new GeneratorError( + 'Invalid value for datasource url' + ); + } + shadowDatabaseUrl = r; + break; + } + } + } + + if (!provider) { + throw new GeneratorError('Datasource is missing "provider" field'); + } + if (!url) { + throw new GeneratorError('Datasource is missing "url" field'); + } + + prisma.addDataSource(dataSource.name, provider, url, shadowDatabaseUrl); + } + + private extractDataSourceUrl(fieldValue: LiteralExpr | InvocationExpr) { + if (this.isStringLiteral(fieldValue)) { + return new PrismaDataSourceUrl(fieldValue.value as string, false); + } else if ( + isInvocationExpr(fieldValue) && + fieldValue.function.ref?.name === 'env' && + fieldValue.args.length === 1 && + this.isStringLiteral(fieldValue.args[0].value) + ) { + return new PrismaDataSourceUrl( + fieldValue.args[0].value.value as string, + true + ); + } else { + return null; + } + } + + private generateGenerator(prisma: PrismaModel) { + prisma.addGenerator( + 'client', + 'prisma-client-js', + path.join(this.context.outDir, '.prisma'), + ['fieldReference', 'interactiveTransactions'] + ); + } + + private generateModel(prisma: PrismaModel, decl: DataModel) { + const model = prisma.addModel(decl.name); + for (const field of decl.fields) { + this.generateModelField(model, field); + } + + // add an "zenstack_guard" field for dealing with pure auth() related conditions + model.addField(GUARD_FIELD_NAME, 'Boolean', [ + new PrismaFieldAttribute('default', [ + new PrismaAttributeArg( + undefined, + new PrismaAttributeArgValue('Boolean', true) + ), + ]), + ]); + + for (const attr of decl.attributes.filter((attr) => + supportedAttrbutes.includes(attr.decl.ref?.name!) + )) { + this.generateModelAttribute(model, attr); + } + } + + private generateModelField(model: PrismaDataModel, field: DataModelField) { + const type = new ModelFieldType( + (field.type.type || field.type.reference?.ref?.name)!, + field.type.array, + field.type.optional + ); + + const attributes = field.attributes + .filter((attr) => supportedAttrbutes.includes(attr.decl.ref?.name!)) + .map((attr) => this.makeFieldAttribute(attr)); + model.addField(field.name, type, attributes); + } + + private makeFieldAttribute(attr: DataModelFieldAttribute) { + return new PrismaFieldAttribute( + attr.decl.ref?.name!, + attr.args.map((arg) => this.makeAttributeArg(arg)) + ); + } + + makeAttributeArg(arg: AttributeArg): PrismaAttributeArg { + return new PrismaAttributeArg( + arg.name, + this.makeAttributeArgValue(arg.value) + ); + } + + makeAttributeArgValue(node: Expression): PrismaAttributeArgValue { + if (isLiteralExpr(node)) { + switch (typeof node.value) { + case 'string': + return new PrismaAttributeArgValue('String', node.value); + case 'number': + return new PrismaAttributeArgValue('Number', node.value); + case 'boolean': + return new PrismaAttributeArgValue('Boolean', node.value); + default: + throw new GeneratorError( + `Unexpected literal type: ${typeof node.value}` + ); + } + } else if (isArrayExpr(node)) { + return new PrismaAttributeArgValue( + 'Array', + new Array( + ...node.items.map((item) => + this.makeAttributeArgValue(item) + ) + ) + ); + } else if (isReferenceExpr(node)) { + return new PrismaAttributeArgValue( + 'FieldReference', + new PrismaFieldReference( + node.target.ref?.name!, + node.args.map( + (arg) => + new PrismaFieldReferenceArg(arg.name, arg.value) + ) + ) + ); + } else if (isInvocationExpr(node)) { + // invocation + return new PrismaAttributeArgValue( + 'FunctionCall', + this.makeFunctionCall(node) + ); + } else { + throw new GeneratorError( + `Unsupported attribute argument expression type: ${node.$type}` + ); + } + } + + makeFunctionCall(node: InvocationExpr): PrismaFunctionCall { + return new PrismaFunctionCall( + node.function.ref?.name!, + node.args.map((arg) => { + if (!isLiteralExpr(arg.value)) { + throw new GeneratorError( + 'Function call argument must be literal' + ); + } + return new PrismaFunctionCallArg(arg.name, arg.value.value); + }) + ); + } + + private generateModelAttribute( + model: PrismaDataModel, + attr: DataModelAttribute + ) { + model.attributes.push( + new PrismaModelAttribute( + attr.decl.ref?.name!, + attr.args.map((arg) => this.makeAttributeArg(arg)) + ) + ); + } + + private generateEnum(prisma: PrismaModel, decl: Enum) { + prisma.addEnum( + decl.name, + decl.fields.map((f) => f.name) + ); + } + + private isStringLiteral(node: AstNode): node is LiteralExpr { + return isLiteralExpr(node) && typeof node.value === 'string'; + } +} diff --git a/packages/schema/src/generator/server/data/data-generator.ts b/packages/schema/src/generator/server/data/data-generator.ts deleted file mode 100644 index 980efe22c..000000000 --- a/packages/schema/src/generator/server/data/data-generator.ts +++ /dev/null @@ -1,483 +0,0 @@ -import { Context, GeneratorError } from '../../types'; -import { - CodeBlockWriter, - OptionalKind, - ParameterDeclarationStructure, - Project, - SourceFile, - VariableDeclarationKind, -} from 'ts-morph'; -import { - DataModel, - Expression, - isInvocationExpr, - isLiteralExpr, -} from '@lang/generated/ast'; -import * as path from 'path'; -import { camelCase, paramCase } from 'change-case'; -import { extractDataModelsWithAllowRules } from '../../utils'; -import { ServerCodeGenerator } from '../server-code-generator'; -import ExpressionWriter from './expression-writer'; -import { streamAllContents } from 'langium'; -import colors from 'colors'; - -type ServerOperation = 'get' | 'create' | 'find' | 'update' | 'del'; -type PolicyAction = 'create' | 'read' | 'update' | 'delete'; - -export default class DataServerGenerator implements ServerCodeGenerator { - generate(project: Project, context: Context): void { - const models = extractDataModelsWithAllowRules(context.schema); - this.generateIndex(models, project, context); - this.generateUtils(project, context); - models.forEach((model) => - this.generateForModel(model, project, context) - ); - - console.log(colors.blue(' ✔️ Server-side CRUD generated')); - } - - //#region Index & Utils - - private generateIndex( - models: DataModel[], - project: Project, - context: Context - ) { - const content = ` - import type { NextApiRequest, NextApiResponse } from 'next'; - import { RequestHandlerOptions } from '..'; - ${models.map((model) => this.writeModelImport(model)).join('\n')} - - export default async function ( - req: NextApiRequest, - res: NextApiResponse, - path: string[], - options: RequestHandlerOptions - ) { - const [type, ...rest] = path; - switch (type) { - ${models - .map((model) => this.writeModelEntrance(model)) - .join('\n')} - default: - res.status(404).json({ error: 'Unknown type: ' + type }); - } - } - `; - const sf = project.createSourceFile( - path.join(context.outDir, 'server/data/index.ts'), - content, - { overwrite: true } - ); - sf.formatText(); - } - - private generateUtils(project: Project, context: Context) { - const content = ` - import type { NextApiRequest, NextApiResponse } from 'next'; - import { RequestHandlerOptions } from '..'; - - export async function getUser( - req: NextApiRequest, - res: NextApiResponse, - options: RequestHandlerOptions - ) { - return await options.getServerUser(req, res); - } - - export function unauthorized(res: NextApiResponse) { - res.status(403).json({ message: 'Unauthorized' }); - } - - export function notFound(res: NextApiResponse) { - res.status(404).json({ message: 'Entity not found' }); - } - `; - const sf = project.createSourceFile( - path.join(context.outDir, 'server/data/_utils.ts'), - content, - { overwrite: true } - ); - sf.formatText(); - } - - private writeModelImport(model: DataModel) { - return `import ${camelCase(model.name)}Handler from './${paramCase( - model.name - )}';`; - } - - private writeModelEntrance(model: DataModel) { - return ` - case '${camelCase(model.name)}': - return ${camelCase(model.name)}Handler(req, res, rest, options); - `; - } - - //#endregion - - //#region Per-Model - - private generateForModel( - model: DataModel, - project: Project, - context: Context - ) { - const content = ` - import type { NextApiRequest, NextApiResponse } from 'next'; - import type { Prisma as P } from '@zenstack/.prisma'; - import { RequestHandlerOptions } from '..'; - import service from '@zenstack/service'; - import { getUser, notFound } from './_utils'; - - export default async function ( - req: NextApiRequest, - res: NextApiResponse, - path: string[], - options: RequestHandlerOptions - ) { - switch (req.method) { - case 'GET': - if (path.length > 0) { - return get(req, res, path[0], options); - } else { - return find(req, res, options); - } - - case 'POST': - return create(req, res, options); - - case 'PUT': - return update(req, res, path[0], options); - - case 'DELETE': - return del(req, res, path[0], options); - - default: - throw new Error('Unsupported HTTP method: ' + req.method); - } - } - `; - const sf = project.createSourceFile( - path.join( - context.outDir, - `server/data/${paramCase(model.name)}.ts` - ), - content, - { overwrite: true } - ); - - this.generateFind(sf, model); - this.generateGet(sf, model); - this.generateCreate(sf, model); - this.generateUpdate(sf, model); - this.generateDel(sf, model); - - sf.formatText(); - sf.saveSync(); - } - - private generateServeFunction( - sourceFile: SourceFile, - model: DataModel, - operation: ServerOperation - ) { - const parameters: OptionalKind[] = []; - - parameters.push({ - name: 'req', - type: 'NextApiRequest', - }); - - parameters.push({ - name: 'res', - type: 'NextApiResponse', - }); - - if ( - operation === 'get' || - operation === 'update' || - operation === 'del' - ) { - // an extra "id" parameter - parameters.push({ - name: 'id', - type: 'string', - }); - } - - parameters.push({ - name: 'options', - type: 'RequestHandlerOptions', - }); - - const func = sourceFile - .addFunction({ - name: operation, - isAsync: true, - parameters, - }) - .addBody(); - - if (this.modelUsesAuth(model)) { - func.addStatements([ - `const user = await getUser(req, res, options);`, - ]); - } - return func; - } - - private modelUsesAuth(model: DataModel) { - return !!streamAllContents(model).find( - (node) => - isInvocationExpr(node) && node.function.ref?.name === 'auth' - ); - } - - //#region Find & Get - - private generateFind(sourceFile: SourceFile, model: DataModel) { - const func = this.generateServeFunction(sourceFile, model, 'find'); - - func.addStatements([ - `const query: P.${model.name}FindManyArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, - ]); - - func.addVariableStatement({ - declarationKind: VariableDeclarationKind.Const, - declarations: [ - { - name: 'args', - type: `P.${model.name}FindManyArgs`, - initializer: (writer) => { - writer.block(() => { - writer.writeLine('...query,'); - writer.write('where:'); - writer.block(() => { - writer.write('AND: ['); - writer.write('{ ...query.where },'); - this.writeFindArgs(writer, model, 'read'); - writer.write(']'); - }); - }); - }, - }, - ], - }); - - func.addStatements([ - `res.status(200).send(await service.db.${camelCase( - model.name - )}.findMany(args));`, - ]); - } - - private generateGet(sourceFile: SourceFile, model: DataModel) { - const func = this.generateServeFunction(sourceFile, model, 'get'); - - func.addStatements([ - `const query: P.${model.name}FindFirstArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, - ]); - - func.addVariableStatement({ - declarationKind: VariableDeclarationKind.Const, - declarations: [ - { - name: 'args', - type: `P.${model.name}FindFirstArgs`, - initializer: (writer) => { - writer.block(() => { - writer.writeLine('...query,'); - writer.write('where:'); - writer.block(() => { - writer.write('AND: ['); - writer.write('{ id },'); - this.writeFindArgs(writer, model, 'read'); - writer.write(']'); - }); - }); - }, - }, - ], - }); - - func.addStatements([ - ` - const r = await service.db.${camelCase(model.name)}.findFirst(args); - if (!r) { - notFound(res); - } else { - res.status(200).send(r); - } - `, - ]); - } - - private writeFindArgs( - writer: CodeBlockWriter, - model: DataModel, - action: PolicyAction - ) { - writer.block(() => { - writer.writeLine('AND: ['); - this.writeDenyRules(writer, model, action); - this.writeAllowRules(writer, model, action); - writer.writeLine(']'); - }); - } - - //#endregion - - //#region Create - - private generateCreate(sourceFile: SourceFile, model: DataModel) { - const func = this.generateServeFunction(sourceFile, model, 'create'); - - func.addVariableStatement({ - declarationKind: VariableDeclarationKind.Const, - declarations: [ - { - name: 'args', - type: `P.${model.name}CreateArgs`, - initializer: 'req.body', - }, - ], - }); - - // TODO: policy - - func.addStatements([ - ` - const r = await service.db.${camelCase(model.name)}.create(args); - res.status(200).send(r); - `, - ]); - } - - //#endregion - - //#region Update - - private generateUpdate(sourceFile: SourceFile, model: DataModel) { - const func = this.generateServeFunction(sourceFile, model, 'update'); - - func.addVariableStatement({ - declarationKind: VariableDeclarationKind.Const, - declarations: [ - { - name: 'body', - type: `P.${model.name}UpdateArgs`, - initializer: 'req.body', - }, - ], - }); - - // TODO: policy - - func.addStatements([ - ` - const r = await service.db.${camelCase(model.name)}.update({ - ...body, - where: { id } - }); - res.status(200).send(r); - `, - ]); - } - - //#endregion - - //#region Delete - - private generateDel(sourceFile: SourceFile, model: DataModel) { - const func = this.generateServeFunction(sourceFile, model, 'del'); - - func.addStatements([ - `const args: P.${model.name}DeleteArgs = req.query.q? (JSON.parse(req.query.q as string)): {};`, - ]); - - // TODO: policy - - func.addStatements([ - ` - const r = await service.db.${camelCase(model.name)}.delete({ - ...args, - where: { id } - }); - res.status(200).send(r); - `, - ]); - } - - //#endregion - - //#endregion - - //#region Policy - - private ruleSpecCovers(ruleSpec: Expression, action: string) { - if (!isLiteralExpr(ruleSpec) || typeof ruleSpec.value !== 'string') { - throw new GeneratorError(`Rule spec must be a string literal`); - } - - const specs = ruleSpec.value.split(',').map((s) => s.trim()); - return specs.includes('all') || specs.includes(action); - } - - private writeDenyRules( - writer: CodeBlockWriter, - model: DataModel, - action: PolicyAction - ) { - const attrs = model.attributes.filter( - (attr) => - attr.args.length > 0 && - attr.decl.ref?.name === 'deny' && - attr.args.length > 1 && - this.ruleSpecCovers(attr.args[0].value, action) - ); - attrs.forEach((attr) => - this.writeDenyRule(writer, model, attr.args[1].value) - ); - } - - private writeDenyRule( - writer: CodeBlockWriter, - model: DataModel, - rule: Expression - ) { - writer.block(() => { - writer.writeLine('NOT: '); - new ExpressionWriter(writer).write(rule); - }); - writer.write(','); - } - - private writeAllowRules( - writer: CodeBlockWriter, - model: DataModel, - action: PolicyAction - ) { - const attrs = model.attributes.filter( - (attr) => - attr.args.length > 0 && - attr.decl.ref?.name === 'allow' && - attr.args.length > 1 && - this.ruleSpecCovers(attr.args[0].value, action) - ); - attrs.forEach((attr) => - this.writeAllowRule(writer, model, attr.args[1].value) - ); - } - - private writeAllowRule( - writer: CodeBlockWriter, - model: DataModel, - rule: Expression - ) { - new ExpressionWriter(writer).write(rule); - writer.write(','); - } - - //#endregion -} diff --git a/packages/schema/src/generator/server/function/function-generator.ts b/packages/schema/src/generator/server/function/function-generator.ts deleted file mode 100644 index f83486cfb..000000000 --- a/packages/schema/src/generator/server/function/function-generator.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Context } from '../../types'; -import { Project } from 'ts-morph'; -import * as path from 'path'; -import { ServerCodeGenerator } from '../server-code-generator'; - -export default class FunctionServerGenerator implements ServerCodeGenerator { - generate(project: Project, context: Context) { - this.generateIndex(project, context); - } - - private generateIndex(project: Project, context: Context) { - const content = ` - import type { NextApiRequest, NextApiResponse } from 'next'; - import { RequestHandlerOptions } from '..'; - - export default async function ( - req: NextApiRequest, - res: NextApiResponse, - path: string[], - options: RequestHandlerOptions - ) { - throw new Error('Not implemented'); - } - `; - const sf = project.createSourceFile( - path.join(context.outDir, 'server/function/index.ts'), - content, - { overwrite: true } - ); - sf.formatText(); - } -} diff --git a/packages/schema/src/generator/server/index.ts b/packages/schema/src/generator/server/index.ts deleted file mode 100644 index e6f7fe3e5..000000000 --- a/packages/schema/src/generator/server/index.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { Project } from 'ts-morph'; -import { Context, Generator } from '../types'; -import * as path from 'path'; -import DataServerGenerator from './data/data-generator'; -import FunctionServerGenerator from './function/function-generator'; - -export default class ServerGenerator implements Generator { - async generate(context: Context) { - const project = new Project(); - - this.generateIndex(project, context); - - new DataServerGenerator().generate(project, context); - new FunctionServerGenerator().generate(project, context); - - await project.save(); - } - - generateIndex(project: Project, context: Context) { - const content = ` - import type { NextApiRequest, NextApiResponse } from 'next'; - import dataHandler from './data'; - import functionHandler from './function'; - - export type AuthUser = { id: string } & Record; - - export type RequestHandlerOptions = { - getServerUser: ( - req: NextApiRequest, - res: NextApiResponse - ) => Promise; - }; - - export function RequestHandler(options: RequestHandlerOptions) { - return async (req: NextApiRequest, res: NextApiResponse) => { - const [route, ...rest] = req.query.path as string[]; - switch (route) { - case 'data': - return dataHandler(req, res, rest, options); - - case 'function': - return functionHandler(req, res, rest, options); - - default: - res.status(404).json({ error: 'Unknown route: ' + route }); - } - }; - } - `; - const sf = project.createSourceFile( - path.join(context.outDir, 'server/index.ts'), - content, - { overwrite: true } - ); - sf.formatText(); - } -} diff --git a/packages/schema/src/generator/server/server-code-generator.ts b/packages/schema/src/generator/server/server-code-generator.ts deleted file mode 100644 index 7849be772..000000000 --- a/packages/schema/src/generator/server/server-code-generator.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { Context } from '../types'; -import { Project } from 'ts-morph'; - -export interface ServerCodeGenerator { - generate(project: Project, context: Context): void; -} diff --git a/packages/schema/src/utils/indent-string.ts b/packages/schema/src/utils/indent-string.ts index f9a52db1a..2c929fead 100644 --- a/packages/schema/src/utils/indent-string.ts +++ b/packages/schema/src/utils/indent-string.ts @@ -2,5 +2,5 @@ export default function indentString(string: string, count = 4) { const indent = ' '; - return string.replace(/^/gm, indent.repeat(count)); + return string.replace(/^(?!\s*$)/gm, indent.repeat(count)); } diff --git a/packages/schema/tests/generator/expression-writer.test.ts b/packages/schema/tests/generator/expression-writer.test.ts index bd1a6ee31..fb2936780 100644 --- a/packages/schema/tests/generator/expression-writer.test.ts +++ b/packages/schema/tests/generator/expression-writer.test.ts @@ -9,7 +9,7 @@ import { import { loadModel } from '../utils'; import * as tmp from 'tmp'; import { GUARD_FIELD_NAME } from '../../src/generator/constants'; -import expressionWriter from '../../src/generator/server/data/expression-writer'; +import expressionWriter from '../../src/generator/prisma/expression-writer'; async function check( schema: string, diff --git a/samples/todo/.env b/samples/todo/.env index 08437b40f..5f276308a 100644 --- a/samples/todo/.env +++ b/samples/todo/.env @@ -3,10 +3,10 @@ GOOGLE_ID=423589857007-uioobc20f8ek0mend4g7qjck4c5a7f1s.apps.googleusercontent.c GOOGLE_SECRET=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 NEXTAUTH_SECRET=abc123 #DATABASE_URL=postgres://postgres:6aXr6Q2fqscnDHA@db.oupzipbojojlbyvaudpl.supabase.co:6543/postgres -#DATABASE_URL="postgresql://postgres:abc123@localhost:5432/todo?schema=public" +DATABASE_URL="postgresql://postgres:abc123@localhost:5432/todo?schema=public" # No Pooling -DATABASE_URL=postgresql://postgres:6aXr6Q2fqscnDHA@db.oupzipbojojlbyvaudpl.supabase.co:5432/postgres?schema=public +# DATABASE_URL=postgresql://postgres:6aXr6Q2fqscnDHA@db.oupzipbojojlbyvaudpl.supabase.co:5432/postgres?schema=public # Pooling #DATABASE_URL=postgres://postgres:6aXr6Q2fqscnDHA@db.oupzipbojojlbyvaudpl.supabase.co:6543/postgres diff --git a/samples/todo/package.json b/samples/todo/package.json index b6dd75a75..936595b62 100644 --- a/samples/todo/package.json +++ b/samples/todo/package.json @@ -15,14 +15,14 @@ }, "dependencies": { "@prisma/client": "^4.4.0", + "@zenstackhq/runtime": "file:../../packages/runtime/lib", "bcryptjs": "^2.4.3", "daisyui": "^2.31.0", "next": "12.3.1", "next-auth": "^4.10.3", "react": "18.2.0", "react-dom": "18.2.0", - "swr": "^1.3.0", - "@zenstackhq/runtime": "file:../../packages/runtime/lib" + "swr": "^1.3.0" }, "devDependencies": { "@types/bcryptjs": "^2.4.2", From b026e14546efe4805256c268c48b3560d06dc905 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Wed, 12 Oct 2022 15:08:04 +0800 Subject: [PATCH 12/15] update --- package.json | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/package.json b/package.json index a65d3649e..603d0c2d8 100644 --- a/package.json +++ b/package.json @@ -3,9 +3,7 @@ "version": "1.0.0", "description": "", "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, + "scripts": {}, "keywords": [], "author": "", "license": "ISC" From 42970eaf8a5a82b0a775e1ec53d13e77067d457b Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Wed, 12 Oct 2022 23:33:14 +0800 Subject: [PATCH 13/15] WIP --- packages/generated/auth.d.ts | 1 + packages/generated/auth.js | 3 + packages/generated/hooks.d.ts | 1 + packages/generated/hooks.js | 3 + packages/generated/index.d.ts | 3 + packages/generated/index.js | 1 + packages/generated/package-lock.json | 13 +++ packages/generated/package.json | 12 +++ packages/generated/types.d.ts | 1 + packages/generated/types.js | 3 + packages/runtime/package.json | 2 +- packages/runtime/tsconfig.json | 2 +- packages/schema/package.json | 3 +- packages/schema/src/cli/index.ts | 36 ++------ packages/schema/src/generator/index.ts | 59 +++++++++++++ .../schema/src/generator/next-auth/index.ts | 6 +- .../src/generator/package.template.json | 9 ++ packages/schema/src/generator/prisma/index.ts | 7 -- .../src/generator/prisma/prisma-builder.ts | 2 +- .../src/generator/prisma/schema-generator.ts | 10 +-- .../schema/src/generator/service/index.ts | 2 +- .../src/generator/tsconfig.template.json | 17 ++++ pnpm-lock.yaml | 12 ++- samples/todo/package-lock.json | 86 ++++++++++++++++--- samples/todo/package.json | 6 +- samples/todo/pages/api/auth/[...nextauth].ts | 7 +- samples/todo/pages/api/zen/[...path].ts | 2 +- samples/todo/pages/index.tsx | 4 +- 28 files changed, 239 insertions(+), 74 deletions(-) create mode 100644 packages/generated/auth.d.ts create mode 100644 packages/generated/auth.js create mode 100644 packages/generated/hooks.d.ts create mode 100644 packages/generated/hooks.js create mode 100644 packages/generated/index.d.ts create mode 100644 packages/generated/index.js create mode 100644 packages/generated/package-lock.json create mode 100644 packages/generated/package.json create mode 100644 packages/generated/types.d.ts create mode 100644 packages/generated/types.js create mode 100644 packages/schema/src/generator/index.ts create mode 100644 packages/schema/src/generator/package.template.json create mode 100644 packages/schema/src/generator/tsconfig.template.json diff --git a/packages/generated/auth.d.ts b/packages/generated/auth.d.ts new file mode 100644 index 000000000..04bff1079 --- /dev/null +++ b/packages/generated/auth.d.ts @@ -0,0 +1 @@ +export * from '.zenstack/auth'; diff --git a/packages/generated/auth.js b/packages/generated/auth.js new file mode 100644 index 000000000..2554a165b --- /dev/null +++ b/packages/generated/auth.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('.zenstack/auth/index'), +}; diff --git a/packages/generated/hooks.d.ts b/packages/generated/hooks.d.ts new file mode 100644 index 000000000..fb0591dd4 --- /dev/null +++ b/packages/generated/hooks.d.ts @@ -0,0 +1 @@ +export * from '.zenstack/hooks'; diff --git a/packages/generated/hooks.js b/packages/generated/hooks.js new file mode 100644 index 000000000..490b856c3 --- /dev/null +++ b/packages/generated/hooks.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('.zenstack/hooks/index'), +}; diff --git a/packages/generated/index.d.ts b/packages/generated/index.d.ts new file mode 100644 index 000000000..05dacffbb --- /dev/null +++ b/packages/generated/index.d.ts @@ -0,0 +1,3 @@ +export * from '.zenstack'; +import service from '.zenstack'; +export default service; diff --git a/packages/generated/index.js b/packages/generated/index.js new file mode 100644 index 000000000..340cb5bd4 --- /dev/null +++ b/packages/generated/index.js @@ -0,0 +1 @@ +module.exports = require('.zenstack/index').default; diff --git a/packages/generated/package-lock.json b/packages/generated/package-lock.json new file mode 100644 index 000000000..e3408a6c3 --- /dev/null +++ b/packages/generated/package-lock.json @@ -0,0 +1,13 @@ +{ + "name": "@zenstackhq/generated", + "version": "0.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@zenstackhq/generated", + "version": "0.1.0", + "license": "MIT" + } + } +} diff --git a/packages/generated/package.json b/packages/generated/package.json new file mode 100644 index 000000000..1c95cbbb0 --- /dev/null +++ b/packages/generated/package.json @@ -0,0 +1,12 @@ +{ + "name": "@zenstackhq/generated", + "version": "0.1.7", + "description": "ZenStack generated code", + "main": "index.js", + "types": "index.d.ts", + "scripts": { + "npm-publish": "pnpm publish --no-git-checks --access public" + }, + "author": "ZenStack", + "license": "MIT" +} diff --git a/packages/generated/types.d.ts b/packages/generated/types.d.ts new file mode 100644 index 000000000..b96c699d5 --- /dev/null +++ b/packages/generated/types.d.ts @@ -0,0 +1 @@ +export * from '.zenstack/.prisma'; diff --git a/packages/generated/types.js b/packages/generated/types.js new file mode 100644 index 000000000..f6e351008 --- /dev/null +++ b/packages/generated/types.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('.zenstack/.prisma/index'), +}; diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 049dbfcf5..3a81f5e32 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/runtime", - "version": "0.1.1", + "version": "0.1.3", "description": "ZenStack runtime library", "main": "lib/index.js", "types": "lib/index.d.ts", diff --git a/packages/runtime/tsconfig.json b/packages/runtime/tsconfig.json index a678f9c39..f58f60c5e 100644 --- a/packages/runtime/tsconfig.json +++ b/packages/runtime/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "target": "ES6", - "module": "ESNext", + "module": "CommonJS", "lib": ["ESNext", "DOM"], "sourceMap": true, "outDir": "lib", diff --git a/packages/schema/package.json b/packages/schema/package.json index ffa1ef2e1..a2a8ecab5 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -49,7 +49,7 @@ "main": "./out/extension.js", "scripts": { "vscode:prepublish": "npm run build && npm run lint", - "build": "tsc && tsc-alias && cp src/language-server/stdlib.zmodel ./out/language-server/", + "build": "tsc && tsc-alias && cp src/language-server/stdlib.zmodel ./out/language-server/ && cp src/generator/*.template.json ./out/generator/", "ts:watch": "tsc --watch", "tsc-alias:watch": "tsc-alias --watch", "lint": "eslint src --ext ts", @@ -65,6 +65,7 @@ "colors": "^1.4.0", "commander": "^8.0.0", "langium": "^0.4.0", + "prisma": "^4.4.0", "promisify": "^0.0.3", "ts-morph": "^16.0.0", "vscode-jsonrpc": "^8.0.2", diff --git a/packages/schema/src/cli/index.ts b/packages/schema/src/cli/index.ts index c6c3a5c87..c723fac28 100644 --- a/packages/schema/src/cli/index.ts +++ b/packages/schema/src/cli/index.ts @@ -4,13 +4,7 @@ import { ZModelLanguageMetaData } from '../language-server/generated/module'; import { createZModelServices } from '../language-server/zmodel-module'; import { extractAstNode } from './cli-util'; import { Context } from '../generator/types'; -import * as path from 'path'; -import * as fs from 'fs'; -import colors from 'colors'; -import PrismaGenerator from '../generator/prisma'; -import ServiceGenerator from '../generator/service'; -import ReactHooksGenerator from '../generator/react-hooks'; -import NextAuthGenerator from '../generator/next-auth'; +import { ZenStackGenerator } from '../generator'; export const generateAction = async ( fileName: string, @@ -21,33 +15,14 @@ export const generateAction = async ( const context: Context = { schema: model, - outDir: path.resolve(opts.destination), + outDir: opts.destination || 'node_modules/.zenstack', }; - if (!fs.existsSync(context.outDir)) { - fs.mkdirSync(context.outDir); - } - - console.log(colors.bold('⌛️ Running ZenStack generators')); - - const generators = [ - new PrismaGenerator(), - new ServiceGenerator(), - new ReactHooksGenerator(), - new NextAuthGenerator(), - ]; - - for (const generator of generators) { - await generator.generate(context); - } - - console.log( - colors.green(colors.bold('👻 All generators completed successfully!')) - ); + await new ZenStackGenerator().generate(context); }; export type GenerateOptions = { - destination: string; + destination?: string; }; export default function (): void { @@ -66,8 +41,7 @@ export default function (): void { ) .option( '-d, --destination ', - 'destination directory of generating', - '.zenstack' + 'destination directory of generating' ) .description( 'generates JavaScript code that prints "Hello, {name}!" for each greeting in a source file' diff --git a/packages/schema/src/generator/index.ts b/packages/schema/src/generator/index.ts new file mode 100644 index 000000000..80116a954 --- /dev/null +++ b/packages/schema/src/generator/index.ts @@ -0,0 +1,59 @@ +import { Context } from './types'; +import * as fs from 'fs'; +import colors from 'colors'; +import PrismaGenerator from './prisma'; +import ServiceGenerator from './service'; +import ReactHooksGenerator from './react-hooks'; +import NextAuthGenerator from './next-auth'; +import path from 'path'; +import { execSync } from 'child_process'; + +export class ZenStackGenerator { + async generate(context: Context) { + if (!fs.existsSync(context.outDir)) { + fs.mkdirSync(context.outDir); + } + + console.log(colors.bold('⌛️ Running ZenStack generators')); + + const generators = [ + new PrismaGenerator(), + new ServiceGenerator(), + new ReactHooksGenerator(), + new NextAuthGenerator(), + ]; + + for (const generator of generators) { + await generator.generate(context); + } + + // generate package.json + const packageJson = require(path.join( + __dirname, + 'package.template.json' + )); + fs.writeFileSync( + path.join(context.outDir, 'package.json'), + JSON.stringify(packageJson, undefined, 4) + ); + + // compile ts sources + const tsConfig = require(path.join( + __dirname, + 'tsconfig.template.json' + )); + fs.writeFileSync( + path.join(context.outDir, 'tsconfig.json'), + JSON.stringify(tsConfig, undefined, 4) + ); + + execSync(`npx tsc -p "${path.join(context.outDir, 'tsconfig.json')}"`); + console.log(colors.blue(' ✔️ Typescript source files transpiled')); + + console.log( + colors.green( + colors.bold('👻 All generators completed successfully!') + ) + ); + } +} diff --git a/packages/schema/src/generator/next-auth/index.ts b/packages/schema/src/generator/next-auth/index.ts index 785c7a678..e9fe4ac80 100644 --- a/packages/schema/src/generator/next-auth/index.ts +++ b/packages/schema/src/generator/next-auth/index.ts @@ -30,9 +30,9 @@ export default class NextAuthGenerator implements Generator { generateAdapter(project: Project, context: Context) { const content = ` - import { ZenStackService } from '../service'; + import { ZenStackService } from '..'; import { Adapter } from 'next-auth/adapters'; - import { Prisma } from '@zenstack/.prisma'; + import { Prisma } from '../.prisma'; export function NextAuthAdapter(service: ZenStackService): Adapter { const db = service.db; @@ -101,7 +101,7 @@ export default class NextAuthGenerator implements Generator { generateAuthorize(project: Project, context: Context) { const content = ` - import { ZenStackService } from '../service'; + import { ZenStackService } from '..'; import { hash, compare } from 'bcryptjs'; async function hashPassword(password: string) { diff --git a/packages/schema/src/generator/package.template.json b/packages/schema/src/generator/package.template.json new file mode 100644 index 000000000..10d648030 --- /dev/null +++ b/packages/schema/src/generator/package.template.json @@ -0,0 +1,9 @@ +{ + "name": ".zenstack", + "version": "1.0.0", + "description": "ZenStack generated code", + "main": "index.js", + "types": "index.d.ts", + "author": "ZenStack", + "license": "MIT" +} diff --git a/packages/schema/src/generator/prisma/index.ts b/packages/schema/src/generator/prisma/index.ts index 8a543096c..419fc90d3 100644 --- a/packages/schema/src/generator/prisma/index.ts +++ b/packages/schema/src/generator/prisma/index.ts @@ -19,13 +19,6 @@ export default class PrismaGenerator implements Generator { } async generatePrismaClient(schemaFile: string) { - try { - execSync('npx prisma -v'); - } catch (err) { - execSync(`npm i prisma @prisma/client`); - console.log(colors.blue(' ✔️ Prisma package installed')); - } - execSync(`npx prisma generate --schema "${schemaFile}"`); } } diff --git a/packages/schema/src/generator/prisma/prisma-builder.ts b/packages/schema/src/generator/prisma/prisma-builder.ts index d8bfc8796..ec1d4bbba 100644 --- a/packages/schema/src/generator/prisma/prisma-builder.ts +++ b/packages/schema/src/generator/prisma/prisma-builder.ts @@ -103,7 +103,7 @@ export class Generator { ? indentString( `previewFeatures = [${this.previewFeatures ?.map((f) => '"' + f + '"') - .join(',')}]\n` + .join(', ')}]\n` ) : '') + `}` diff --git a/packages/schema/src/generator/prisma/schema-generator.ts b/packages/schema/src/generator/prisma/schema-generator.ts index e0a267284..ed9a2d8a8 100644 --- a/packages/schema/src/generator/prisma/schema-generator.ts +++ b/packages/schema/src/generator/prisma/schema-generator.ts @@ -153,12 +153,10 @@ export default class PrismaSchemaGenerator { } private generateGenerator(prisma: PrismaModel) { - prisma.addGenerator( - 'client', - 'prisma-client-js', - path.join(this.context.outDir, '.prisma'), - ['fieldReference', 'interactiveTransactions'] - ); + prisma.addGenerator('client', 'prisma-client-js', '.prisma', [ + 'fieldReference', + 'interactiveTransactions', + ]); } private generateModel(prisma: PrismaModel, decl: DataModel) { diff --git a/packages/schema/src/generator/service/index.ts b/packages/schema/src/generator/service/index.ts index 8155c311c..43b59c03e 100644 --- a/packages/schema/src/generator/service/index.ts +++ b/packages/schema/src/generator/service/index.ts @@ -8,7 +8,7 @@ export default class ServiceGenerator implements Generator { async generate(context: Context) { const project = new Project(); const sf = project.createSourceFile( - path.join(context.outDir, 'service.ts'), + path.join(context.outDir, 'index.ts'), undefined, { overwrite: true } ); diff --git a/packages/schema/src/generator/tsconfig.template.json b/packages/schema/src/generator/tsconfig.template.json new file mode 100644 index 000000000..7818bb7d9 --- /dev/null +++ b/packages/schema/src/generator/tsconfig.template.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES6", + "module": "CommonJS", + "lib": ["ESNext", "DOM"], + "sourceMap": true, + "outDir": ".", + "strict": true, + "moduleResolution": "node", + "esModuleInterop": true, + "skipLibCheck": true, + "declaration": true, + "resolveJsonModule": true + }, + "include": ["**/*.ts"], + "exclude": ["node_modules", ".prisma"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9085e8b73..0c9821829 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -56,6 +56,7 @@ importers: jest: ^29.0.3 langium: ^0.4.0 langium-cli: ^0.4.0 + prisma: ^4.4.0 promisify: ^0.0.3 tmp: ^0.2.1 ts-jest: ^29.0.1 @@ -75,6 +76,7 @@ importers: colors: 1.4.0 commander: 8.3.0 langium: 0.4.0 + prisma: 4.4.0 promisify: 0.0.3 ts-morph: 16.0.0 vscode-jsonrpc: 8.0.2 @@ -984,7 +986,6 @@ packages: /@prisma/engines/4.4.0: resolution: {integrity: sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==} requiresBuild: true - dev: true /@prisma/fetch-engine/4.4.0: resolution: {integrity: sha512-3a+f/HPvJl9XYj8IuX57/rHM8cYZuqS+R+jXx/ZPRwvELVlvVeE81GTTSMvtXguyfHXgKW7wKjiJqZm7tGw/WA==} @@ -3794,6 +3795,15 @@ packages: react-is: 18.2.0 dev: true + /prisma/4.4.0: + resolution: {integrity: sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==} + engines: {node: '>=14.17'} + hasBin: true + requiresBuild: true + dependencies: + '@prisma/engines': 4.4.0 + dev: false + /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: true diff --git a/samples/todo/package-lock.json b/samples/todo/package-lock.json index 9c038bcb4..3d13c677e 100644 --- a/samples/todo/package-lock.json +++ b/samples/todo/package-lock.json @@ -9,7 +9,8 @@ "version": "0.1.0", "dependencies": { "@prisma/client": "^4.4.0", - "@zenstackhq/runtime": "file:../../packages/runtime/lib", + "@zenstackhq/generated": "latest", + "@zenstackhq/runtime": "latest", "bcryptjs": "^2.4.3", "daisyui": "^2.31.0", "next": "12.3.1", @@ -27,11 +28,17 @@ "eslint": "^7.19.0", "eslint-config-next": "12.3.1", "postcss": "^8.4.16", + "prisma": "^4.4.0", "tailwindcss": "^3.1.8", "typescript": "^4.6.2" } }, - "../../packages/runtime/lib": {}, + "../../packages/generated": { + "name": "@zenstackhq/generated", + "version": "0.1.1", + "extraneous": true, + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -472,9 +479,8 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.4.0.tgz", "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==", - "hasInstallScript": true, - "optional": true, - "peer": true + "devOptional": true, + "hasInstallScript": true }, "node_modules/@prisma/engines-version": { "version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6", @@ -655,9 +661,24 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@zenstackhq/generated": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@zenstackhq/generated/-/generated-0.1.7.tgz", + "integrity": "sha512-KhR5vTU2R1a2MCkl8P91VjrnlnLTcsWI0O5gGO+H9TAlebR89m+4hc1Urat0gYyWNTzDGmnIXS1vwOf+ufRzow==" + }, "node_modules/@zenstackhq/runtime": { - "resolved": "../../packages/runtime/lib", - "link": true + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@zenstackhq/runtime/-/runtime-0.1.3.tgz", + "integrity": "sha512-uOy9YsqbTQWAdzE59FuwuihfcgQeImUqXsmVl/J6XntRpVDzuLYalK3FczaIVr7gJp1jsuR0TvO2HfskGNOKHw==", + "dependencies": { + "deepcopy": "^2.1.0", + "swr": "^1.3.0" + }, + "peerDependencies": { + "next": "12.3.1", + "react": "^17.0.2 || ^18", + "react-dom": "^17.0.2 || ^18" + } }, "node_modules/acorn": { "version": "7.4.1", @@ -1211,6 +1232,14 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepcopy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-2.1.0.tgz", + "integrity": "sha512-8cZeTb1ZKC3bdSCP6XOM1IsTczIO73fdqtwa2B0N15eAz7gmyhQo+mc5gnFuulsgN3vIQYmTgbmQVKalH1dKvQ==", + "dependencies": { + "type-detect": "^4.0.8" + } + }, "node_modules/define-properties": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", @@ -3185,9 +3214,8 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.4.0.tgz", "integrity": "sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==", + "devOptional": true, "hasInstallScript": true, - "optional": true, - "peer": true, "dependencies": { "@prisma/engines": "4.4.0" }, @@ -3853,6 +3881,14 @@ "node": ">= 0.8.0" } }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "engines": { + "node": ">=4" + } + }, "node_modules/type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", @@ -4291,8 +4327,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-4.4.0.tgz", "integrity": "sha512-Fpykccxlt9MHrAs/QpPGpI2nOiRxuLA+LiApgA59ibbf24YICZIMWd3SI2YD+q0IAIso0jCGiHhirAIbxK3RyQ==", - "optional": true, - "peer": true + "devOptional": true }, "@prisma/engines-version": { "version": "4.4.0-66.f352a33b70356f46311da8b00d83386dd9f145d6", @@ -4424,8 +4459,19 @@ } } }, + "@zenstackhq/generated": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@zenstackhq/generated/-/generated-0.1.7.tgz", + "integrity": "sha512-KhR5vTU2R1a2MCkl8P91VjrnlnLTcsWI0O5gGO+H9TAlebR89m+4hc1Urat0gYyWNTzDGmnIXS1vwOf+ufRzow==" + }, "@zenstackhq/runtime": { - "version": "file:../../packages/runtime/lib" + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@zenstackhq/runtime/-/runtime-0.1.3.tgz", + "integrity": "sha512-uOy9YsqbTQWAdzE59FuwuihfcgQeImUqXsmVl/J6XntRpVDzuLYalK3FczaIVr7gJp1jsuR0TvO2HfskGNOKHw==", + "requires": { + "deepcopy": "^2.1.0", + "swr": "^1.3.0" + } }, "acorn": { "version": "7.4.1", @@ -4807,6 +4853,14 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "deepcopy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-2.1.0.tgz", + "integrity": "sha512-8cZeTb1ZKC3bdSCP6XOM1IsTczIO73fdqtwa2B0N15eAz7gmyhQo+mc5gnFuulsgN3vIQYmTgbmQVKalH1dKvQ==", + "requires": { + "type-detect": "^4.0.8" + } + }, "define-properties": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", @@ -6221,8 +6275,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/prisma/-/prisma-4.4.0.tgz", "integrity": "sha512-l/QKLmLcKJQFuc+X02LyICo0NWTUVaNNZ00jKJBqwDyhwMAhboD1FWwYV50rkH4Wls0RviAJSFzkC2ZrfawpfA==", - "optional": true, - "peer": true, + "devOptional": true, "requires": { "@prisma/engines": "4.4.0" } @@ -6693,6 +6746,11 @@ "prelude-ls": "^1.2.1" } }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==" + }, "type-fest": { "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", diff --git a/samples/todo/package.json b/samples/todo/package.json index 936595b62..0b342e1d3 100644 --- a/samples/todo/package.json +++ b/samples/todo/package.json @@ -11,11 +11,12 @@ "db-push": "prisma db push --schema .zenstack/schema.prisma", "db-migrate": "prisma migrate dev --schema .zenstack/schema.prisma", "db-reset": "prisma migrate reset --schema .zenstack/schema.prisma", - "generate": "node ../../packages/schema/bin/cli generate ./schema.zmodel --destination .zenstack" + "generate": "node ../../packages/schema/bin/cli generate ./schema.zmodel" }, "dependencies": { "@prisma/client": "^4.4.0", - "@zenstackhq/runtime": "file:../../packages/runtime/lib", + "@zenstackhq/generated": "latest", + "@zenstackhq/runtime": "latest", "bcryptjs": "^2.4.3", "daisyui": "^2.31.0", "next": "12.3.1", @@ -33,6 +34,7 @@ "eslint": "^7.19.0", "eslint-config-next": "12.3.1", "postcss": "^8.4.16", + "prisma": "^4.4.0", "tailwindcss": "^3.1.8", "typescript": "^4.6.2" } diff --git a/samples/todo/pages/api/auth/[...nextauth].ts b/samples/todo/pages/api/auth/[...nextauth].ts index 1c791fcc1..7c891a975 100644 --- a/samples/todo/pages/api/auth/[...nextauth].ts +++ b/samples/todo/pages/api/auth/[...nextauth].ts @@ -1,8 +1,11 @@ import NextAuth, { NextAuthOptions } from 'next-auth'; import CredentialsProvider from 'next-auth/providers/credentials'; import GoogleProvider from 'next-auth/providers/google'; -import { authorize, NextAuthAdapter as Adapter } from '@zenstack/auth'; -import service from '@zenstack/service'; +import { + authorize, + NextAuthAdapter as Adapter, +} from '@zenstackhq/generated/auth'; +import service from '@zenstackhq/generated'; export const authOptions: NextAuthOptions = { // Configure one or more authentication providers diff --git a/samples/todo/pages/api/zen/[...path].ts b/samples/todo/pages/api/zen/[...path].ts index fe6d8bbaa..8b83c3f2a 100644 --- a/samples/todo/pages/api/zen/[...path].ts +++ b/samples/todo/pages/api/zen/[...path].ts @@ -5,7 +5,7 @@ import { } from '@zenstackhq/runtime'; import { authOptions } from '@api/auth/[...nextauth]'; import { unstable_getServerSession } from 'next-auth'; -import service from '@zenstack/service'; +import service from '@zenstackhq/generated'; const options: RequestHandlerOptions = { async getServerUser(req: NextApiRequest, res: NextApiResponse) { diff --git a/samples/todo/pages/index.tsx b/samples/todo/pages/index.tsx index 3b3d0edfd..be07c1ab0 100644 --- a/samples/todo/pages/index.tsx +++ b/samples/todo/pages/index.tsx @@ -1,8 +1,8 @@ import type { NextPage } from 'next'; import LoginButton from '../components/LoginButton'; import { useSession } from 'next-auth/react'; -import { useTodoCollection } from '@zenstack/hooks'; -import { SpaceUserRole, TodoCollection } from '@zenstack/.prisma'; +import { useTodoCollection } from '@zenstackhq/generated/hooks'; +import { TodoCollection } from '@zenstackhq/generated/types'; const Home: NextPage = () => { const { data: session } = useSession(); From b0a394b8474e20b23200ec96a7e00fbff63fa5c8 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Thu, 13 Oct 2022 12:08:16 +0800 Subject: [PATCH 14/15] WIP --- .npmrc | 1 + packages/generated/auth.d.ts | 1 - packages/generated/auth.js | 3 - packages/generated/hooks.d.ts | 1 - packages/generated/hooks.js | 3 - packages/generated/index.d.ts | 3 - packages/generated/index.js | 1 - packages/generated/package-lock.json | 13 - packages/generated/package.json | 12 - packages/generated/types.js | 3 - packages/{runtime => internal}/.gitignore | 0 packages/{runtime => internal}/jest.config.ts | 0 packages/internal/package.json | 40 + .../src/handler/data/handler.ts | 0 .../src/handler/data/query-processor.ts | 0 .../src/handler/index.ts | 0 .../src/handler/types.ts | 0 packages/{runtime => internal}/src/index.ts | 0 .../src/request-handler.ts | 2 +- packages/{runtime => internal}/src/request.ts | 0 .../src/request/index.ts | 0 packages/{runtime => internal}/src/types.ts | 0 .../tests/query-processor.test.ts | 0 packages/{runtime => internal}/tsconfig.json | 0 packages/runtime/auth.d.ts | 1 + packages/runtime/auth.js | 3 + packages/runtime/hooks.d.ts | 1 + packages/runtime/hooks.js | 3 + packages/runtime/index.d.ts | 3 + packages/runtime/index.js | 1 + packages/runtime/package-lock.json | 753 +++++++++++ packages/runtime/package.json | 42 +- packages/runtime/server.d.ts | 1 + packages/runtime/server.js | 3 + packages/{generated => runtime}/types.d.ts | 0 packages/runtime/types.js | 3 + packages/schema/package.json | 12 +- packages/schema/src/generator/constants.ts | 3 +- packages/schema/src/generator/index.ts | 20 +- .../schema/src/generator/next-auth/index.ts | 8 +- .../src/generator/package.template.json | 4 +- .../generator/prisma/query-gard-generator.ts | 10 +- .../schema/src/generator/react-hooks/index.ts | 13 +- .../schema/src/generator/service/index.ts | 8 +- .../src/generator/tsconfig.template.json | 4 +- pnpm-lock.yaml | 87 +- samples/todo/package-lock.json | 1121 ++++++++++++++--- samples/todo/package.json | 9 +- samples/todo/pages/api/auth/[...nextauth].ts | 4 +- samples/todo/pages/api/hello.ts | 13 - .../pages/api/{zen => zenstack}/[...path].ts | 8 +- samples/todo/pages/index.tsx | 4 +- 52 files changed, 1865 insertions(+), 360 deletions(-) delete mode 100644 packages/generated/auth.d.ts delete mode 100644 packages/generated/auth.js delete mode 100644 packages/generated/hooks.d.ts delete mode 100644 packages/generated/hooks.js delete mode 100644 packages/generated/index.d.ts delete mode 100644 packages/generated/index.js delete mode 100644 packages/generated/package-lock.json delete mode 100644 packages/generated/package.json delete mode 100644 packages/generated/types.js rename packages/{runtime => internal}/.gitignore (100%) rename packages/{runtime => internal}/jest.config.ts (100%) create mode 100644 packages/internal/package.json rename packages/{runtime => internal}/src/handler/data/handler.ts (100%) rename packages/{runtime => internal}/src/handler/data/query-processor.ts (100%) rename packages/{runtime => internal}/src/handler/index.ts (100%) rename packages/{runtime => internal}/src/handler/types.ts (100%) rename packages/{runtime => internal}/src/index.ts (100%) rename packages/{runtime => internal}/src/request-handler.ts (94%) rename packages/{runtime => internal}/src/request.ts (100%) rename packages/{runtime => internal}/src/request/index.ts (100%) rename packages/{runtime => internal}/src/types.ts (100%) rename packages/{runtime => internal}/tests/query-processor.test.ts (100%) rename packages/{runtime => internal}/tsconfig.json (100%) create mode 100644 packages/runtime/auth.d.ts create mode 100644 packages/runtime/auth.js create mode 100644 packages/runtime/hooks.d.ts create mode 100644 packages/runtime/hooks.js create mode 100644 packages/runtime/index.d.ts create mode 100644 packages/runtime/index.js create mode 100644 packages/runtime/package-lock.json create mode 100644 packages/runtime/server.d.ts create mode 100644 packages/runtime/server.js rename packages/{generated => runtime}/types.d.ts (100%) create mode 100644 packages/runtime/types.js delete mode 100644 samples/todo/pages/api/hello.ts rename samples/todo/pages/api/{zen => zenstack}/[...path].ts (74%) diff --git a/.npmrc b/.npmrc index 3e775efb0..0b634b898 100644 --- a/.npmrc +++ b/.npmrc @@ -1 +1,2 @@ auto-install-peers=true +git-checks=false diff --git a/packages/generated/auth.d.ts b/packages/generated/auth.d.ts deleted file mode 100644 index 04bff1079..000000000 --- a/packages/generated/auth.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '.zenstack/auth'; diff --git a/packages/generated/auth.js b/packages/generated/auth.js deleted file mode 100644 index 2554a165b..000000000 --- a/packages/generated/auth.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - ...require('.zenstack/auth/index'), -}; diff --git a/packages/generated/hooks.d.ts b/packages/generated/hooks.d.ts deleted file mode 100644 index fb0591dd4..000000000 --- a/packages/generated/hooks.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from '.zenstack/hooks'; diff --git a/packages/generated/hooks.js b/packages/generated/hooks.js deleted file mode 100644 index 490b856c3..000000000 --- a/packages/generated/hooks.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - ...require('.zenstack/hooks/index'), -}; diff --git a/packages/generated/index.d.ts b/packages/generated/index.d.ts deleted file mode 100644 index 05dacffbb..000000000 --- a/packages/generated/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from '.zenstack'; -import service from '.zenstack'; -export default service; diff --git a/packages/generated/index.js b/packages/generated/index.js deleted file mode 100644 index 340cb5bd4..000000000 --- a/packages/generated/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('.zenstack/index').default; diff --git a/packages/generated/package-lock.json b/packages/generated/package-lock.json deleted file mode 100644 index e3408a6c3..000000000 --- a/packages/generated/package-lock.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "@zenstackhq/generated", - "version": "0.1.0", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "@zenstackhq/generated", - "version": "0.1.0", - "license": "MIT" - } - } -} diff --git a/packages/generated/package.json b/packages/generated/package.json deleted file mode 100644 index 1c95cbbb0..000000000 --- a/packages/generated/package.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "name": "@zenstackhq/generated", - "version": "0.1.7", - "description": "ZenStack generated code", - "main": "index.js", - "types": "index.d.ts", - "scripts": { - "npm-publish": "pnpm publish --no-git-checks --access public" - }, - "author": "ZenStack", - "license": "MIT" -} diff --git a/packages/generated/types.js b/packages/generated/types.js deleted file mode 100644 index f6e351008..000000000 --- a/packages/generated/types.js +++ /dev/null @@ -1,3 +0,0 @@ -module.exports = { - ...require('.zenstack/.prisma/index'), -}; diff --git a/packages/runtime/.gitignore b/packages/internal/.gitignore similarity index 100% rename from packages/runtime/.gitignore rename to packages/internal/.gitignore diff --git a/packages/runtime/jest.config.ts b/packages/internal/jest.config.ts similarity index 100% rename from packages/runtime/jest.config.ts rename to packages/internal/jest.config.ts diff --git a/packages/internal/package.json b/packages/internal/package.json new file mode 100644 index 000000000..a4f35c6fa --- /dev/null +++ b/packages/internal/package.json @@ -0,0 +1,40 @@ +{ + "name": "@zenstackhq/internal", + "version": "0.1.6", + "description": "ZenStack internal runtime library", + "main": "lib/index.js", + "types": "lib/index.d.ts", + "scripts": { + "build": "tsc", + "watch": "tsc --watch", + "test": "jest", + "prepublishOnly": "pnpm build" + }, + "keywords": [], + "author": "", + "license": "ISC", + "files": [ + "lib/**/*" + ], + "dependencies": { + "bcryptjs": "^2.4.3", + "deepcopy": "^2.1.0", + "swr": "^1.3.0" + }, + "peerDependencies": { + "next": "12.3.1", + "react": "^17.0.2 || ^18", + "react-dom": "^17.0.2 || ^18" + }, + "devDependencies": { + "@types/bcryptjs": "^2.4.2", + "@types/jest": "^29.0.3", + "@types/node": "^14.18.29", + "jest": "^29.0.3", + "ts-jest": "^29.0.1", + "ts-node": "^10.9.1", + "tsc-alias": "^1.7.0", + "tsconfig-paths-jest": "^0.0.1", + "typescript": "^4.6.2" + } +} diff --git a/packages/runtime/src/handler/data/handler.ts b/packages/internal/src/handler/data/handler.ts similarity index 100% rename from packages/runtime/src/handler/data/handler.ts rename to packages/internal/src/handler/data/handler.ts diff --git a/packages/runtime/src/handler/data/query-processor.ts b/packages/internal/src/handler/data/query-processor.ts similarity index 100% rename from packages/runtime/src/handler/data/query-processor.ts rename to packages/internal/src/handler/data/query-processor.ts diff --git a/packages/runtime/src/handler/index.ts b/packages/internal/src/handler/index.ts similarity index 100% rename from packages/runtime/src/handler/index.ts rename to packages/internal/src/handler/index.ts diff --git a/packages/runtime/src/handler/types.ts b/packages/internal/src/handler/types.ts similarity index 100% rename from packages/runtime/src/handler/types.ts rename to packages/internal/src/handler/types.ts diff --git a/packages/runtime/src/index.ts b/packages/internal/src/index.ts similarity index 100% rename from packages/runtime/src/index.ts rename to packages/internal/src/index.ts diff --git a/packages/runtime/src/request-handler.ts b/packages/internal/src/request-handler.ts similarity index 94% rename from packages/runtime/src/request-handler.ts rename to packages/internal/src/request-handler.ts index 85fb11566..839650dbf 100644 --- a/packages/runtime/src/request-handler.ts +++ b/packages/internal/src/request-handler.ts @@ -9,7 +9,7 @@ export type RequestHandlerOptions = { ) => Promise; }; -export function RequestHandler( +export function requestHandler( service: Service, options: RequestHandlerOptions ) { diff --git a/packages/runtime/src/request.ts b/packages/internal/src/request.ts similarity index 100% rename from packages/runtime/src/request.ts rename to packages/internal/src/request.ts diff --git a/packages/runtime/src/request/index.ts b/packages/internal/src/request/index.ts similarity index 100% rename from packages/runtime/src/request/index.ts rename to packages/internal/src/request/index.ts diff --git a/packages/runtime/src/types.ts b/packages/internal/src/types.ts similarity index 100% rename from packages/runtime/src/types.ts rename to packages/internal/src/types.ts diff --git a/packages/runtime/tests/query-processor.test.ts b/packages/internal/tests/query-processor.test.ts similarity index 100% rename from packages/runtime/tests/query-processor.test.ts rename to packages/internal/tests/query-processor.test.ts diff --git a/packages/runtime/tsconfig.json b/packages/internal/tsconfig.json similarity index 100% rename from packages/runtime/tsconfig.json rename to packages/internal/tsconfig.json diff --git a/packages/runtime/auth.d.ts b/packages/runtime/auth.d.ts new file mode 100644 index 000000000..279619b14 --- /dev/null +++ b/packages/runtime/auth.d.ts @@ -0,0 +1 @@ +export * from '.zenstack/lib/auth'; diff --git a/packages/runtime/auth.js b/packages/runtime/auth.js new file mode 100644 index 000000000..d8348f834 --- /dev/null +++ b/packages/runtime/auth.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('.zenstack/lib/auth'), +}; diff --git a/packages/runtime/hooks.d.ts b/packages/runtime/hooks.d.ts new file mode 100644 index 000000000..6394aede2 --- /dev/null +++ b/packages/runtime/hooks.d.ts @@ -0,0 +1 @@ +export * from '.zenstack/lib/hooks'; diff --git a/packages/runtime/hooks.js b/packages/runtime/hooks.js new file mode 100644 index 000000000..ad58e14f8 --- /dev/null +++ b/packages/runtime/hooks.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('.zenstack/lib/hooks'), +}; diff --git a/packages/runtime/index.d.ts b/packages/runtime/index.d.ts new file mode 100644 index 000000000..4353bf5db --- /dev/null +++ b/packages/runtime/index.d.ts @@ -0,0 +1,3 @@ +export * from '.zenstack/lib'; +import service from '.zenstack/lib'; +export default service; diff --git a/packages/runtime/index.js b/packages/runtime/index.js new file mode 100644 index 000000000..d2848e8ac --- /dev/null +++ b/packages/runtime/index.js @@ -0,0 +1 @@ +module.exports = require('.zenstack/lib').default; diff --git a/packages/runtime/package-lock.json b/packages/runtime/package-lock.json new file mode 100644 index 000000000..fccd2ceab --- /dev/null +++ b/packages/runtime/package-lock.json @@ -0,0 +1,753 @@ +{ + "name": "@zenstackhq/client", + "version": "0.1.7", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "@zenstackhq/client", + "version": "0.1.7", + "license": "MIT", + "peerDependencies": { + "@zenstackhq/runtime": "latest" + } + }, + "node_modules/@next/env": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.1.tgz", + "integrity": "sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==", + "peer": true + }, + "node_modules/@next/swc-android-arm-eabi": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.1.tgz", + "integrity": "sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-android-arm64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.1.tgz", + "integrity": "sha512-CmgU2ZNyBP0rkugOOqLnjl3+eRpXBzB/I2sjwcGZ7/Z6RcUJXK5Evz+N0ucOxqE4cZ3gkTeXtSzRrMK2mGYV8Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.1.tgz", + "integrity": "sha512-hT/EBGNcu0ITiuWDYU9ur57Oa4LybD5DOQp4f22T6zLfpoBMfBibPtR8XktXmOyFHrL/6FC2p9ojdLZhWhvBHg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.1.tgz", + "integrity": "sha512-9S6EVueCVCyGf2vuiLiGEHZCJcPAxglyckTZcEwLdJwozLqN0gtS0Eq0bQlGS3dH49Py/rQYpZ3KVWZ9BUf/WA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-freebsd-x64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.1.tgz", + "integrity": "sha512-qcuUQkaBZWqzM0F1N4AkAh88lLzzpfE6ImOcI1P6YeyJSsBmpBIV8o70zV+Wxpc26yV9vpzb+e5gCyxNjKJg5Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm-gnueabihf": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.1.tgz", + "integrity": "sha512-diL9MSYrEI5nY2wc/h/DBewEDUzr/DqBjIgHJ3RUNtETAOB3spMNHvJk2XKUDjnQuluLmFMloet9tpEqU2TT9w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.1.tgz", + "integrity": "sha512-o/xB2nztoaC7jnXU3Q36vGgOolJpsGG8ETNjxM1VAPxRwM7FyGCPHOMk1XavG88QZSQf+1r+POBW0tLxQOJ9DQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.1.tgz", + "integrity": "sha512-2WEasRxJzgAmP43glFNhADpe8zB7kJofhEAVNbDJZANp+H4+wq+/cW1CdDi8DqjkShPEA6/ejJw+xnEyDID2jg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.1.tgz", + "integrity": "sha512-JWEaMyvNrXuM3dyy9Pp5cFPuSSvG82+yABqsWugjWlvfmnlnx9HOQZY23bFq3cNghy5V/t0iPb6cffzRWylgsA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.1.tgz", + "integrity": "sha512-xoEWQQ71waWc4BZcOjmatuvPUXKTv6MbIFzpm4LFeCHsg2iwai0ILmNXf81rJR+L1Wb9ifEke2sQpZSPNz1Iyg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.1.tgz", + "integrity": "sha512-hswVFYQYIeGHE2JYaBVtvqmBQ1CppplQbZJS/JgrVI3x2CurNhEkmds/yqvDONfwfbttTtH4+q9Dzf/WVl3Opw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.1.tgz", + "integrity": "sha512-Kny5JBehkTbKPmqulr5i+iKntO5YMP+bVM8Hf8UAmjSMVo3wehyLVc9IZkNmcbxi+vwETnQvJaT5ynYBkJ9dWA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.1.tgz", + "integrity": "sha512-W1ijvzzg+kPEX6LAc+50EYYSEo0FVu7dmTE+t+DM4iOLqgGHoW9uYSz9wCVdkXOEEMP9xhXfGpcSxsfDucyPkA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@swc/helpers": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz", + "integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==", + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@zenstackhq/runtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@zenstackhq/runtime/-/runtime-0.1.3.tgz", + "integrity": "sha512-uOy9YsqbTQWAdzE59FuwuihfcgQeImUqXsmVl/J6XntRpVDzuLYalK3FczaIVr7gJp1jsuR0TvO2HfskGNOKHw==", + "peer": true, + "dependencies": { + "deepcopy": "^2.1.0", + "swr": "^1.3.0" + }, + "peerDependencies": { + "next": "12.3.1", + "react": "^17.0.2 || ^18", + "react-dom": "^17.0.2 || ^18" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001418", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", + "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ], + "peer": true + }, + "node_modules/deepcopy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-2.1.0.tgz", + "integrity": "sha512-8cZeTb1ZKC3bdSCP6XOM1IsTczIO73fdqtwa2B0N15eAz7gmyhQo+mc5gnFuulsgN3vIQYmTgbmQVKalH1dKvQ==", + "peer": true, + "dependencies": { + "type-detect": "^4.0.8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "peer": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/next": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/next/-/next-12.3.1.tgz", + "integrity": "sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==", + "peer": true, + "dependencies": { + "@next/env": "12.3.1", + "@swc/helpers": "0.4.11", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.0.7", + "use-sync-external-store": "1.2.0" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=12.22.0" + }, + "optionalDependencies": { + "@next/swc-android-arm-eabi": "12.3.1", + "@next/swc-android-arm64": "12.3.1", + "@next/swc-darwin-arm64": "12.3.1", + "@next/swc-darwin-x64": "12.3.1", + "@next/swc-freebsd-x64": "12.3.1", + "@next/swc-linux-arm-gnueabihf": "12.3.1", + "@next/swc-linux-arm64-gnu": "12.3.1", + "@next/swc-linux-arm64-musl": "12.3.1", + "@next/swc-linux-x64-gnu": "12.3.1", + "@next/swc-linux-x64-musl": "12.3.1", + "@next/swc-win32-arm64-msvc": "12.3.1", + "@next/swc-win32-ia32-msvc": "12.3.1", + "@next/swc-win32-x64-msvc": "12.3.1" + }, + "peerDependencies": { + "fibers": ">= 3.1.0", + "node-sass": "^6.0.0 || ^7.0.0", + "react": "^17.0.2 || ^18.0.0-0", + "react-dom": "^17.0.2 || ^18.0.0-0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "fibers": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "peer": true + }, + "node_modules/postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], + "peer": true, + "dependencies": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/styled-jsx": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz", + "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==", + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/swr": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/swr/-/swr-1.3.0.tgz", + "integrity": "sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==", + "peer": true, + "peerDependencies": { + "react": "^16.11.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "peer": true + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peer": true, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + } + }, + "dependencies": { + "@next/env": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-12.3.1.tgz", + "integrity": "sha512-9P9THmRFVKGKt9DYqeC2aKIxm8rlvkK38V1P1sRE7qyoPBIs8l9oo79QoSdPtOWfzkbDAVUqvbQGgTMsb8BtJg==", + "peer": true + }, + "@next/swc-android-arm-eabi": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm-eabi/-/swc-android-arm-eabi-12.3.1.tgz", + "integrity": "sha512-i+BvKA8tB//srVPPQxIQN5lvfROcfv4OB23/L1nXznP+N/TyKL8lql3l7oo2LNhnH66zWhfoemg3Q4VJZSruzQ==", + "optional": true, + "peer": true + }, + "@next/swc-android-arm64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-android-arm64/-/swc-android-arm64-12.3.1.tgz", + "integrity": "sha512-CmgU2ZNyBP0rkugOOqLnjl3+eRpXBzB/I2sjwcGZ7/Z6RcUJXK5Evz+N0ucOxqE4cZ3gkTeXtSzRrMK2mGYV8Q==", + "optional": true, + "peer": true + }, + "@next/swc-darwin-arm64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-12.3.1.tgz", + "integrity": "sha512-hT/EBGNcu0ITiuWDYU9ur57Oa4LybD5DOQp4f22T6zLfpoBMfBibPtR8XktXmOyFHrL/6FC2p9ojdLZhWhvBHg==", + "optional": true, + "peer": true + }, + "@next/swc-darwin-x64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-12.3.1.tgz", + "integrity": "sha512-9S6EVueCVCyGf2vuiLiGEHZCJcPAxglyckTZcEwLdJwozLqN0gtS0Eq0bQlGS3dH49Py/rQYpZ3KVWZ9BUf/WA==", + "optional": true, + "peer": true + }, + "@next/swc-freebsd-x64": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-freebsd-x64/-/swc-freebsd-x64-12.3.1.tgz", + "integrity": "sha512-qcuUQkaBZWqzM0F1N4AkAh88lLzzpfE6ImOcI1P6YeyJSsBmpBIV8o70zV+Wxpc26yV9vpzb+e5gCyxNjKJg5Q==", + "optional": true, + "peer": true + }, + "@next/swc-linux-arm-gnueabihf": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm-gnueabihf/-/swc-linux-arm-gnueabihf-12.3.1.tgz", + "integrity": "sha512-diL9MSYrEI5nY2wc/h/DBewEDUzr/DqBjIgHJ3RUNtETAOB3spMNHvJk2XKUDjnQuluLmFMloet9tpEqU2TT9w==", + "optional": true, + "peer": true + }, + "@next/swc-linux-arm64-gnu": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-12.3.1.tgz", + "integrity": "sha512-o/xB2nztoaC7jnXU3Q36vGgOolJpsGG8ETNjxM1VAPxRwM7FyGCPHOMk1XavG88QZSQf+1r+POBW0tLxQOJ9DQ==", + "optional": true, + "peer": true + }, + "@next/swc-linux-arm64-musl": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-12.3.1.tgz", + "integrity": "sha512-2WEasRxJzgAmP43glFNhADpe8zB7kJofhEAVNbDJZANp+H4+wq+/cW1CdDi8DqjkShPEA6/ejJw+xnEyDID2jg==", + "optional": true, + "peer": true + }, + "@next/swc-linux-x64-gnu": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-12.3.1.tgz", + "integrity": "sha512-JWEaMyvNrXuM3dyy9Pp5cFPuSSvG82+yABqsWugjWlvfmnlnx9HOQZY23bFq3cNghy5V/t0iPb6cffzRWylgsA==", + "optional": true, + "peer": true + }, + "@next/swc-linux-x64-musl": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-12.3.1.tgz", + "integrity": "sha512-xoEWQQ71waWc4BZcOjmatuvPUXKTv6MbIFzpm4LFeCHsg2iwai0ILmNXf81rJR+L1Wb9ifEke2sQpZSPNz1Iyg==", + "optional": true, + "peer": true + }, + "@next/swc-win32-arm64-msvc": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-12.3.1.tgz", + "integrity": "sha512-hswVFYQYIeGHE2JYaBVtvqmBQ1CppplQbZJS/JgrVI3x2CurNhEkmds/yqvDONfwfbttTtH4+q9Dzf/WVl3Opw==", + "optional": true, + "peer": true + }, + "@next/swc-win32-ia32-msvc": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-12.3.1.tgz", + "integrity": "sha512-Kny5JBehkTbKPmqulr5i+iKntO5YMP+bVM8Hf8UAmjSMVo3wehyLVc9IZkNmcbxi+vwETnQvJaT5ynYBkJ9dWA==", + "optional": true, + "peer": true + }, + "@next/swc-win32-x64-msvc": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-12.3.1.tgz", + "integrity": "sha512-W1ijvzzg+kPEX6LAc+50EYYSEo0FVu7dmTE+t+DM4iOLqgGHoW9uYSz9wCVdkXOEEMP9xhXfGpcSxsfDucyPkA==", + "optional": true, + "peer": true + }, + "@swc/helpers": { + "version": "0.4.11", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.4.11.tgz", + "integrity": "sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==", + "peer": true, + "requires": { + "tslib": "^2.4.0" + } + }, + "@zenstackhq/runtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@zenstackhq/runtime/-/runtime-0.1.3.tgz", + "integrity": "sha512-uOy9YsqbTQWAdzE59FuwuihfcgQeImUqXsmVl/J6XntRpVDzuLYalK3FczaIVr7gJp1jsuR0TvO2HfskGNOKHw==", + "peer": true, + "requires": { + "deepcopy": "^2.1.0", + "swr": "^1.3.0" + } + }, + "caniuse-lite": { + "version": "1.0.30001418", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", + "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==", + "peer": true + }, + "deepcopy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/deepcopy/-/deepcopy-2.1.0.tgz", + "integrity": "sha512-8cZeTb1ZKC3bdSCP6XOM1IsTczIO73fdqtwa2B0N15eAz7gmyhQo+mc5gnFuulsgN3vIQYmTgbmQVKalH1dKvQ==", + "peer": true, + "requires": { + "type-detect": "^4.0.8" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "peer": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "peer": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "nanoid": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz", + "integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==", + "peer": true + }, + "next": { + "version": "12.3.1", + "resolved": "https://registry.npmjs.org/next/-/next-12.3.1.tgz", + "integrity": "sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==", + "peer": true, + "requires": { + "@next/env": "12.3.1", + "@next/swc-android-arm-eabi": "12.3.1", + "@next/swc-android-arm64": "12.3.1", + "@next/swc-darwin-arm64": "12.3.1", + "@next/swc-darwin-x64": "12.3.1", + "@next/swc-freebsd-x64": "12.3.1", + "@next/swc-linux-arm-gnueabihf": "12.3.1", + "@next/swc-linux-arm64-gnu": "12.3.1", + "@next/swc-linux-arm64-musl": "12.3.1", + "@next/swc-linux-x64-gnu": "12.3.1", + "@next/swc-linux-x64-musl": "12.3.1", + "@next/swc-win32-arm64-msvc": "12.3.1", + "@next/swc-win32-ia32-msvc": "12.3.1", + "@next/swc-win32-x64-msvc": "12.3.1", + "@swc/helpers": "0.4.11", + "caniuse-lite": "^1.0.30001406", + "postcss": "8.4.14", + "styled-jsx": "5.0.7", + "use-sync-external-store": "1.2.0" + } + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "peer": true + }, + "postcss": { + "version": "8.4.14", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz", + "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==", + "peer": true, + "requires": { + "nanoid": "^3.3.4", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, + "requires": { + "loose-envify": "^1.1.0" + } + }, + "react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "peer": true, + "requires": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + } + }, + "scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "peer": true, + "requires": { + "loose-envify": "^1.1.0" + } + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "peer": true + }, + "styled-jsx": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.7.tgz", + "integrity": "sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==", + "peer": true, + "requires": {} + }, + "swr": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/swr/-/swr-1.3.0.tgz", + "integrity": "sha512-dkghQrOl2ORX9HYrMDtPa7LTVHJjCTeZoB1dqTbnnEDlSvN8JEKpYIYurDfvbQFUUS8Cg8PceFVZNkW0KNNYPw==", + "peer": true, + "requires": {} + }, + "tslib": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz", + "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==", + "peer": true + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "peer": true + }, + "use-sync-external-store": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", + "peer": true, + "requires": {} + } + } +} diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 3a81f5e32..7f8ae185d 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,38 +1,14 @@ { "name": "@zenstackhq/runtime", - "version": "0.1.3", - "description": "ZenStack runtime library", - "main": "lib/index.js", - "types": "lib/index.d.ts", - "scripts": { - "build": "tsc", - "watch": "tsc --watch", - "test": "jest", - "npm-publish": "pnpm build && pnpm publish --no-git-checks --access public" - }, - "keywords": [], - "author": "", - "license": "ISC", - "files": [ - "lib/**/*" - ], - "dependencies": { - "deepcopy": "^2.1.0", - "swr": "^1.3.0" - }, + "version": "0.1.17", + "description": "ZenStack generated runtime code", + "main": "index.js", + "types": "index.d.ts", "peerDependencies": { - "next": "12.3.1", - "react": "^17.0.2 || ^18", - "react-dom": "^17.0.2 || ^18" + "@zenstackhq/internal": "^0.1.0", + "bcryptjs": "^2.4.3", + "@types/bcryptjs": "^2.4.2" }, - "devDependencies": { - "@types/jest": "^29.0.3", - "@types/node": "^14.18.29", - "jest": "^29.0.3", - "ts-jest": "^29.0.1", - "ts-node": "^10.9.1", - "tsc-alias": "^1.7.0", - "tsconfig-paths-jest": "^0.0.1", - "typescript": "^4.6.2" - } + "author": "ZenStack", + "license": "MIT" } diff --git a/packages/runtime/server.d.ts b/packages/runtime/server.d.ts new file mode 100644 index 000000000..78e8b9bb2 --- /dev/null +++ b/packages/runtime/server.d.ts @@ -0,0 +1 @@ +export * from '@zenstackhq/internal'; diff --git a/packages/runtime/server.js b/packages/runtime/server.js new file mode 100644 index 000000000..427500501 --- /dev/null +++ b/packages/runtime/server.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('@zenstackhq/internal'), +}; diff --git a/packages/generated/types.d.ts b/packages/runtime/types.d.ts similarity index 100% rename from packages/generated/types.d.ts rename to packages/runtime/types.d.ts diff --git a/packages/runtime/types.js b/packages/runtime/types.js new file mode 100644 index 000000000..a638f1a17 --- /dev/null +++ b/packages/runtime/types.js @@ -0,0 +1,3 @@ +module.exports = { + ...require('.zenstack/.prisma'), +}; diff --git a/packages/schema/package.json b/packages/schema/package.json index a2a8ecab5..73bbcd8f1 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -2,7 +2,7 @@ "name": "zenstack", "displayName": "ZenStack CLI and Language Tools", "description": "ZenStack CLI and Language Tools", - "version": "0.1.0", + "version": "0.1.19", "engines": { "vscode": "^1.56.0" }, @@ -40,11 +40,10 @@ ], "files": [ "bin", - "out", - "src" + "out" ], "bin": { - "zmodel-cli": "./bin/cli" + "zenstack": "./bin/cli" }, "main": "./out/extension.js", "scripts": { @@ -56,10 +55,11 @@ "langium:generate": "langium generate", "langium:watch": "langium generate --watch", "watch": "concurrently --kill-others \"npm:langium:watch\" \"npm:ts:watch\" \"npm:tsc-alias:watch\"", - "test": "jest" + "test": "jest", + "prepublishOnly": "pnpm build" }, "dependencies": { - "@zenstackhq/runtime": "workspace:0.1.1", + "@zenstackhq/internal": "workspace:*", "change-case": "^4.1.2", "chevrotain": "^9.1.0", "colors": "^1.4.0", diff --git a/packages/schema/src/generator/constants.ts b/packages/schema/src/generator/constants.ts index fb202ca08..9d08cb0b4 100644 --- a/packages/schema/src/generator/constants.ts +++ b/packages/schema/src/generator/constants.ts @@ -1,2 +1,3 @@ -export const RUNTIME_PACKAGE = '@zenstackhq/runtime'; +export const INTERNAL_PACKAGE = '@zenstackhq/internal'; export const GUARD_FIELD_NAME = 'zenstack_guard'; +export const API_ROUTE_NAME = 'zenstack'; diff --git a/packages/schema/src/generator/index.ts b/packages/schema/src/generator/index.ts index 80116a954..90261bf1a 100644 --- a/packages/schema/src/generator/index.ts +++ b/packages/schema/src/generator/index.ts @@ -10,9 +10,10 @@ import { execSync } from 'child_process'; export class ZenStackGenerator { async generate(context: Context) { - if (!fs.existsSync(context.outDir)) { - fs.mkdirSync(context.outDir); + if (fs.existsSync(context.outDir)) { + fs.rmSync(context.outDir, { force: true, recursive: true }); } + fs.mkdirSync(context.outDir); console.log(colors.bold('⌛️ Running ZenStack generators')); @@ -47,7 +48,20 @@ export class ZenStackGenerator { JSON.stringify(tsConfig, undefined, 4) ); - execSync(`npx tsc -p "${path.join(context.outDir, 'tsconfig.json')}"`); + try { + execSync( + `npx tsc -p "${path.join(context.outDir, 'tsconfig.json')}"`, + { encoding: 'utf-8', stdio: 'inherit' } + ); + } catch { + console.error( + colors.red( + 'Something went wrong, generated runtime code failed to compile...' + ) + ); + return; + } + console.log(colors.blue(' ✔️ Typescript source files transpiled')); console.log( diff --git a/packages/schema/src/generator/next-auth/index.ts b/packages/schema/src/generator/next-auth/index.ts index e9fe4ac80..e4947e3e1 100644 --- a/packages/schema/src/generator/next-auth/index.ts +++ b/packages/schema/src/generator/next-auth/index.ts @@ -15,7 +15,7 @@ export default class NextAuthGenerator implements Generator { generateIndex(project: Project, context: Context) { const sf = project.createSourceFile( - path.join(context.outDir, 'auth/index.ts'), + path.join(context.outDir, 'src/auth/index.ts'), undefined, { overwrite: true } ); @@ -32,7 +32,7 @@ export default class NextAuthGenerator implements Generator { const content = ` import { ZenStackService } from '..'; import { Adapter } from 'next-auth/adapters'; - import { Prisma } from '../.prisma'; + import { Prisma } from '../../.prisma'; export function NextAuthAdapter(service: ZenStackService): Adapter { const db = service.db; @@ -91,7 +91,7 @@ export default class NextAuthGenerator implements Generator { `; const sf = project.createSourceFile( - path.join(context.outDir, 'auth/next-auth-adapter.ts'), + path.join(context.outDir, 'src/auth/next-auth-adapter.ts'), content, { overwrite: true } ); @@ -173,7 +173,7 @@ export default class NextAuthGenerator implements Generator { `; const sf = project.createSourceFile( - path.join(context.outDir, 'auth/authorize.ts'), + path.join(context.outDir, 'src/auth/authorize.ts'), content, { overwrite: true } ); diff --git a/packages/schema/src/generator/package.template.json b/packages/schema/src/generator/package.template.json index 10d648030..0cc1fd604 100644 --- a/packages/schema/src/generator/package.template.json +++ b/packages/schema/src/generator/package.template.json @@ -2,8 +2,8 @@ "name": ".zenstack", "version": "1.0.0", "description": "ZenStack generated code", - "main": "index.js", - "types": "index.d.ts", + "main": "lib/index.js", + "types": "lib/index.d.ts", "author": "ZenStack", "license": "MIT" } diff --git a/packages/schema/src/generator/prisma/query-gard-generator.ts b/packages/schema/src/generator/prisma/query-gard-generator.ts index f1bc42366..16672127a 100644 --- a/packages/schema/src/generator/prisma/query-gard-generator.ts +++ b/packages/schema/src/generator/prisma/query-gard-generator.ts @@ -4,10 +4,10 @@ import { isEnum, isLiteralExpr, } from '@lang/generated/ast'; -import { PolicyKind, PolicyOperationKind } from '@zenstackhq/runtime'; +import { PolicyKind, PolicyOperationKind } from '@zenstackhq/internal'; import path from 'path'; import { Project, SourceFile, VariableDeclarationKind } from 'ts-morph'; -import { GUARD_FIELD_NAME, RUNTIME_PACKAGE } from '../constants'; +import { GUARD_FIELD_NAME, INTERNAL_PACKAGE } from '../constants'; import { Context } from '../types'; import ExpressionWriter from './expression-writer'; @@ -17,14 +17,14 @@ export default class QueryGuardGenerator { async generate() { const project = new Project(); const sf = project.createSourceFile( - path.join(this.context.outDir, 'query/guard.ts'), + path.join(this.context.outDir, 'src/query/guard.ts'), undefined, { overwrite: true } ); sf.addImportDeclaration({ namedImports: [{ name: 'QueryContext' }], - moduleSpecifier: RUNTIME_PACKAGE, + moduleSpecifier: INTERNAL_PACKAGE, isTypeOnly: true, }); @@ -34,7 +34,7 @@ export default class QueryGuardGenerator { )) { sf.addImportDeclaration({ namedImports: [{ name: e.name }], - moduleSpecifier: '../.prisma', + moduleSpecifier: '../../.prisma', }); } diff --git a/packages/schema/src/generator/react-hooks/index.ts b/packages/schema/src/generator/react-hooks/index.ts index e361bdd7c..24fe01a89 100644 --- a/packages/schema/src/generator/react-hooks/index.ts +++ b/packages/schema/src/generator/react-hooks/index.ts @@ -5,6 +5,7 @@ import { paramCase } from 'change-case'; import { DataModel } from '@lang/generated/ast'; import colors from 'colors'; import { extractDataModelsWithAllowRules } from '../utils'; +import { API_ROUTE_NAME } from '../constants'; export default class ReactHooksGenerator implements Generator { async generate(context: Context) { @@ -102,7 +103,7 @@ export default class ReactHooksGenerator implements Generator { `; const sf = project.createSourceFile( - path.join(context.outDir, `hooks/request.ts`), + path.join(context.outDir, `src/hooks/request.ts`), content, { overwrite: true } ); @@ -116,7 +117,7 @@ export default class ReactHooksGenerator implements Generator { ) { const fileName = paramCase(model.name); const sf = project.createSourceFile( - path.join(context.outDir, `hooks/${fileName}.ts`), + path.join(context.outDir, `src/hooks/${fileName}.ts`), undefined, { overwrite: true } ); @@ -124,12 +125,14 @@ export default class ReactHooksGenerator implements Generator { sf.addImportDeclaration({ namedImports: [{ name: 'Prisma', alias: 'P' }, model.name], isTypeOnly: true, - moduleSpecifier: '../.prisma', + moduleSpecifier: '../../.prisma', }); sf.addStatements([`import * as request from './request';`]); - sf.addStatements(`const endpoint = '/api/zen/data/${model.name}';`); + sf.addStatements( + `const endpoint = '/api/${API_ROUTE_NAME}/data/${model.name}';` + ); const useFuncBody = sf .addFunction({ @@ -251,7 +254,7 @@ export default class ReactHooksGenerator implements Generator { models: DataModel[] ) { const sf = project.createSourceFile( - path.join(context.outDir, 'hooks/index.ts'), + path.join(context.outDir, 'src/hooks/index.ts'), undefined, { overwrite: true } ); diff --git a/packages/schema/src/generator/service/index.ts b/packages/schema/src/generator/service/index.ts index 43b59c03e..5f1114a70 100644 --- a/packages/schema/src/generator/service/index.ts +++ b/packages/schema/src/generator/service/index.ts @@ -2,25 +2,25 @@ import { Context, Generator } from '../types'; import { Project, StructureKind } from 'ts-morph'; import * as path from 'path'; import colors from 'colors'; -import { RUNTIME_PACKAGE } from '../constants'; +import { INTERNAL_PACKAGE } from '../constants'; export default class ServiceGenerator implements Generator { async generate(context: Context) { const project = new Project(); const sf = project.createSourceFile( - path.join(context.outDir, 'index.ts'), + path.join(context.outDir, 'src/index.ts'), undefined, { overwrite: true } ); sf.addImportDeclaration({ namedImports: ['PrismaClient'], - moduleSpecifier: './.prisma', + moduleSpecifier: '../.prisma', }); sf.addImportDeclaration({ namedImports: ['Service', 'PolicyOperationKind', 'QueryContext'], - moduleSpecifier: RUNTIME_PACKAGE, + moduleSpecifier: INTERNAL_PACKAGE, isTypeOnly: true, }); diff --git a/packages/schema/src/generator/tsconfig.template.json b/packages/schema/src/generator/tsconfig.template.json index 7818bb7d9..21606d617 100644 --- a/packages/schema/src/generator/tsconfig.template.json +++ b/packages/schema/src/generator/tsconfig.template.json @@ -4,7 +4,7 @@ "module": "CommonJS", "lib": ["ESNext", "DOM"], "sourceMap": true, - "outDir": ".", + "outDir": "lib", "strict": true, "moduleResolution": "node", "esModuleInterop": true, @@ -13,5 +13,5 @@ "resolveJsonModule": true }, "include": ["**/*.ts"], - "exclude": ["node_modules", ".prisma"] + "exclude": ["node_modules", ".prisma", "**/*.d.ts"] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0c9821829..29c7c98e3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,10 +5,12 @@ importers: .: specifiers: {} - packages/runtime: + packages/internal: specifiers: + '@types/bcryptjs': ^2.4.2 '@types/jest': ^29.0.3 '@types/node': ^14.18.29 + bcryptjs: ^2.4.3 deepcopy: ^2.1.0 jest: ^29.0.3 next: 12.3.1 @@ -21,12 +23,14 @@ importers: tsconfig-paths-jest: ^0.0.1 typescript: ^4.6.2 dependencies: + bcryptjs: 2.4.3 deepcopy: 2.1.0 - next: 12.3.1_biqbaboplfbrettd7655fr4n2y + next: 12.3.1_6tziyx3dehkoeijunclpkpolha react: 18.2.0 react-dom: 18.2.0_react@18.2.0 swr: 1.3.0_react@18.2.0 devDependencies: + '@types/bcryptjs': 2.4.2 '@types/jest': 29.0.3 '@types/node': 14.18.29 jest: 29.0.3_johvxhudwcpndp4mle25vwrlq4 @@ -36,6 +40,17 @@ importers: tsconfig-paths-jest: 0.0.1 typescript: 4.8.3 + packages/runtime: + specifiers: + '@types/bcryptjs': ^2.4.2 + '@zenstackhq/internal': ^0.1.0 + bcryptjs: ^2.4.3 + dependencies: + '@zenstackhq/internal': link:../internal + bcryptjs: 2.4.3 + devDependencies: + '@types/bcryptjs': 2.4.2 + packages/schema: specifiers: '@prisma/internals': ^4.4.0 @@ -46,7 +61,7 @@ importers: '@types/vscode': ^1.56.0 '@typescript-eslint/eslint-plugin': ^4.14.1 '@typescript-eslint/parser': ^4.14.1 - '@zenstackhq/runtime': workspace:0.1.1 + '@zenstackhq/internal': workspace:* change-case: ^4.1.2 chevrotain: ^9.1.0 colors: ^1.4.0 @@ -70,7 +85,7 @@ importers: vscode-languageserver: ^7.0.0 vscode-uri: ^3.0.2 dependencies: - '@zenstackhq/runtime': link:../runtime + '@zenstackhq/internal': link:../internal change-case: 4.1.2 chevrotain: 9.1.0 colors: 1.4.0 @@ -111,7 +126,6 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.1.1 '@jridgewell/trace-mapping': 0.3.16 - dev: true /@babel/code-frame/7.12.11: resolution: {integrity: sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==} @@ -124,12 +138,10 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.18.6 - dev: true /@babel/compat-data/7.19.4: resolution: {integrity: sha512-CHIGpJcUQ5lU9KrPHTjBMhVwQG6CQjxfg36fGXl3qk/Gik1WwWachaXFuo0uCWJT/mStOKtcbFJCaVLihC1CMw==} engines: {node: '>=6.9.0'} - dev: true /@babel/core/7.19.3: resolution: {integrity: sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==} @@ -152,7 +164,6 @@ packages: semver: 6.3.0 transitivePeerDependencies: - supports-color - dev: true /@babel/generator/7.19.5: resolution: {integrity: sha512-DxbNz9Lz4aMZ99qPpO1raTbcrI1ZeYh+9NR9qhfkQIbFtVEqotHojEBxHzmxhVONkGt6VyrqVQcgpefMy9pqcg==} @@ -161,7 +172,6 @@ packages: '@babel/types': 7.19.4 '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 - dev: true /@babel/helper-compilation-targets/7.19.3_@babel+core@7.19.3: resolution: {integrity: sha512-65ESqLGyGmLvgR0mst5AdW1FkNlj9rQsCKduzEoEPhBCDFGXvz2jW6bXFG6i0/MrV2s7hhXjjb2yAzcPuQlLwg==} @@ -174,12 +184,10 @@ packages: '@babel/helper-validator-option': 7.18.6 browserslist: 4.21.4 semver: 6.3.0 - dev: true /@babel/helper-environment-visitor/7.18.9: resolution: {integrity: sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-function-name/7.19.0: resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==} @@ -187,21 +195,18 @@ packages: dependencies: '@babel/template': 7.18.10 '@babel/types': 7.19.4 - dev: true /@babel/helper-hoist-variables/7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.19.4 - dev: true /@babel/helper-module-imports/7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.19.4 - dev: true /@babel/helper-module-transforms/7.19.0: resolution: {integrity: sha512-3HBZ377Fe14RbLIA+ac3sY4PTgpxHVkFrESaWhoI5PuyXPBBX8+C34qblV9G89ZtycGJCmCI/Ut+VUDK4bltNQ==} @@ -217,7 +222,6 @@ packages: '@babel/types': 7.19.4 transitivePeerDependencies: - supports-color - dev: true /@babel/helper-plugin-utils/7.19.0: resolution: {integrity: sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw==} @@ -229,29 +233,24 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.19.4 - dev: true /@babel/helper-split-export-declaration/7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.19.4 - dev: true /@babel/helper-string-parser/7.19.4: resolution: {integrity: sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-validator-identifier/7.19.1: resolution: {integrity: sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==} engines: {node: '>=6.9.0'} - dev: true /@babel/helper-validator-option/7.18.6: resolution: {integrity: sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==} engines: {node: '>=6.9.0'} - dev: true /@babel/helpers/7.19.4: resolution: {integrity: sha512-G+z3aOx2nfDHwX/kyVii5fJq+bgscg89/dJNWpYeKeBv3v9xX8EIabmx1k6u9LS04H7nROFVRVK+e3k0VHp+sw==} @@ -262,7 +261,6 @@ packages: '@babel/types': 7.19.4 transitivePeerDependencies: - supports-color - dev: true /@babel/highlight/7.18.6: resolution: {integrity: sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==} @@ -271,7 +269,6 @@ packages: '@babel/helper-validator-identifier': 7.19.1 chalk: 2.4.2 js-tokens: 4.0.0 - dev: true /@babel/parser/7.19.4: resolution: {integrity: sha512-qpVT7gtuOLjWeDTKLkJ6sryqLliBaFpAtGeqw5cs5giLldvh+Ch0plqnUMKoVAUS6ZEueQQiZV+p5pxtPitEsA==} @@ -279,7 +276,6 @@ packages: hasBin: true dependencies: '@babel/types': 7.19.4 - dev: true /@babel/plugin-syntax-async-generators/7.8.4_@babel+core@7.19.3: resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} @@ -417,7 +413,6 @@ packages: '@babel/code-frame': 7.18.6 '@babel/parser': 7.19.4 '@babel/types': 7.19.4 - dev: true /@babel/traverse/7.19.4: resolution: {integrity: sha512-w3K1i+V5u2aJUOXBFFC5pveFLmtq1s3qcdDNC2qRI6WPBQIDaKFqXxDEqDO/h1dQ3HjsZoZMyIy6jGLq0xtw+g==} @@ -435,7 +430,6 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: true /@babel/types/7.19.4: resolution: {integrity: sha512-M5LK7nAeS6+9j7hAq+b3fQs+pNfUtTGq+yFFfHnauFA8zQtLRfmuipmsKDKKLuyG+wC8ABW43A153YNawNTEtw==} @@ -444,7 +438,6 @@ packages: '@babel/helper-string-parser': 7.19.4 '@babel/helper-validator-identifier': 7.19.1 to-fast-properties: 2.0.0 - dev: true /@bcoe/v8-coverage/0.2.3: resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} @@ -731,7 +724,6 @@ packages: dependencies: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.14 - dev: true /@jridgewell/gen-mapping/0.3.2: resolution: {integrity: sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==} @@ -740,28 +732,23 @@ packages: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.14 '@jridgewell/trace-mapping': 0.3.16 - dev: true /@jridgewell/resolve-uri/3.1.0: resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/set-array/1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} - dev: true /@jridgewell/sourcemap-codec/1.4.14: resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==} - dev: true /@jridgewell/trace-mapping/0.3.16: resolution: {integrity: sha512-LCQ+NeThyJ4k1W2d+vIKdxuSt9R3pQSZ4P92m7EakaYuXcVWbHuT5bjNcqLd4Rdgi6xYWYDvBJZJLZSLanjDcA==} dependencies: '@jridgewell/resolve-uri': 3.1.0 '@jridgewell/sourcemap-codec': 1.4.14 - dev: true /@jridgewell/trace-mapping/0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} @@ -1168,6 +1155,10 @@ packages: '@babel/types': 7.19.4 dev: true + /@types/bcryptjs/2.4.2: + resolution: {integrity: sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==} + dev: true + /@types/cross-spawn/6.0.2: resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==} dependencies: @@ -1451,7 +1442,6 @@ packages: engines: {node: '>=4'} dependencies: color-convert: 1.9.3 - dev: true /ansi-styles/4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} @@ -1614,6 +1604,10 @@ packages: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} dev: true + /bcryptjs/2.4.3: + resolution: {integrity: sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==} + dev: false + /binary-extensions/2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} @@ -1653,7 +1647,6 @@ packages: electron-to-chromium: 1.4.257 node-releases: 2.0.6 update-browserslist-db: 1.0.9_browserslist@4.21.4 - dev: true /bs-logger/0.2.6: resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} @@ -1723,7 +1716,6 @@ packages: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - dev: true /chalk/4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} @@ -1858,7 +1850,6 @@ packages: resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} dependencies: color-name: 1.1.3 - dev: true /color-convert/2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} @@ -1869,7 +1860,6 @@ packages: /color-name/1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true /color-name/1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -1937,7 +1927,6 @@ packages: /convert-source-map/1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} - dev: true /core-util-is/1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -1990,7 +1979,6 @@ packages: optional: true dependencies: ms: 2.1.2 - dev: true /dedent/0.7.0: resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==} @@ -2074,7 +2062,6 @@ packages: /electron-to-chromium/1.4.257: resolution: {integrity: sha512-C65sIwHqNnPC2ADMfse/jWTtmhZMII+x6ADI9gENzrOiI7BpxmfKFE84WkIEl5wEg+7+SfIkwChDlsd1Erju2A==} - dev: true /emittery/0.10.2: resolution: {integrity: sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==} @@ -2112,12 +2099,10 @@ packages: /escalade/3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} engines: {node: '>=6'} - dev: true /escape-string-regexp/1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} - dev: true /escape-string-regexp/2.0.0: resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} @@ -2431,7 +2416,6 @@ packages: /gensync/1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - dev: true /get-caller-file/2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} @@ -2475,7 +2459,6 @@ packages: /globals/11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} engines: {node: '>=4'} - dev: true /globals/13.17.0: resolution: {integrity: sha512-1C+6nQRb1GwGMKm2dH/E7enFAMxGTmGI7/dEdhy/DNelv85w9B72t3uc5frtMNXIbzrarJJ/lTCjcaZwbLJmyw==} @@ -2503,7 +2486,6 @@ packages: /has-flag/3.0.0: resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} engines: {node: '>=4'} - dev: true /has-flag/4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -3229,7 +3211,6 @@ packages: resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} engines: {node: '>=4'} hasBin: true - dev: true /json-parse-even-better-errors/2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} @@ -3251,7 +3232,6 @@ packages: resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==} engines: {node: '>=6'} hasBin: true - dev: true /jsonfile/6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} @@ -3454,7 +3434,6 @@ packages: /ms/2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true /ms/2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -3480,7 +3459,7 @@ packages: engines: {node: '>=10'} dev: true - /next/12.3.1_biqbaboplfbrettd7655fr4n2y: + /next/12.3.1_6tziyx3dehkoeijunclpkpolha: resolution: {integrity: sha512-l7bvmSeIwX5lp07WtIiP9u2ytZMv7jIeB8iacR28PuUEFG5j0HGAPnMqyG5kbZNBG2H7tRsrQ4HCjuMOPnANZw==} engines: {node: '>=12.22.0'} hasBin: true @@ -3504,7 +3483,7 @@ packages: postcss: 8.4.14 react: 18.2.0 react-dom: 18.2.0_react@18.2.0 - styled-jsx: 5.0.7_react@18.2.0 + styled-jsx: 5.0.7_b6k74wvxdvqypha4emuv7fd2ke use-sync-external-store: 1.2.0_react@18.2.0 optionalDependencies: '@next/swc-android-arm-eabi': 12.3.1 @@ -3550,7 +3529,6 @@ packages: /node-releases/2.0.6: resolution: {integrity: sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==} - dev: true /normalize-package-data/2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -4024,7 +4002,6 @@ packages: /semver/6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true - dev: true /semver/7.3.7: resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==} @@ -4207,7 +4184,7 @@ packages: engines: {node: '>=8'} dev: true - /styled-jsx/5.0.7_react@18.2.0: + /styled-jsx/5.0.7_b6k74wvxdvqypha4emuv7fd2ke: resolution: {integrity: sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==} engines: {node: '>= 12.0.0'} peerDependencies: @@ -4220,6 +4197,7 @@ packages: babel-plugin-macros: optional: true dependencies: + '@babel/core': 7.19.3 react: 18.2.0 dev: false @@ -4228,7 +4206,6 @@ packages: engines: {node: '>=4'} dependencies: has-flag: 3.0.0 - dev: true /supports-color/7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -4354,7 +4331,6 @@ packages: /to-fast-properties/2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} engines: {node: '>=4'} - dev: true /to-regex-range/5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} @@ -4548,7 +4524,6 @@ packages: browserslist: 4.21.4 escalade: 3.1.1 picocolors: 1.0.0 - dev: true /upper-case-first/2.0.2: resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} diff --git a/samples/todo/package-lock.json b/samples/todo/package-lock.json index 3d13c677e..8f42db18e 100644 --- a/samples/todo/package-lock.json +++ b/samples/todo/package-lock.json @@ -9,9 +9,7 @@ "version": "0.1.0", "dependencies": { "@prisma/client": "^4.4.0", - "@zenstackhq/generated": "latest", "@zenstackhq/runtime": "latest", - "bcryptjs": "^2.4.3", "daisyui": "^2.31.0", "next": "12.3.1", "next-auth": "^4.10.3", @@ -20,7 +18,6 @@ "swr": "^1.3.0" }, "devDependencies": { - "@types/bcryptjs": "^2.4.2", "@types/node": "^14.17.3", "@types/react": "18.0.21", "@types/react-dom": "18.0.6", @@ -28,17 +25,11 @@ "eslint": "^7.19.0", "eslint-config-next": "12.3.1", "postcss": "^8.4.16", - "prisma": "^4.4.0", "tailwindcss": "^3.1.8", - "typescript": "^4.6.2" + "typescript": "^4.6.2", + "zenstack": "latest" } }, - "../../packages/generated": { - "name": "@zenstackhq/generated", - "version": "0.1.1", - "extraneous": true, - "license": "MIT" - }, "node_modules/@babel/code-frame": { "version": "7.12.11", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", @@ -143,9 +134,9 @@ } }, "node_modules/@babel/runtime": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", - "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz", + "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==", "dependencies": { "regenerator-runtime": "^0.13.4" }, @@ -154,9 +145,9 @@ } }, "node_modules/@babel/runtime-corejs3": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz", - "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.4.tgz", + "integrity": "sha512-HzjQ8+dzdx7dmZy4DQ8KV8aHi/74AjEbBGTFutBmg/pd3dY5/q1sfuOGPTFGEytlQhWoeVXqcK5BwMgIkRkNDQ==", "dev": true, "dependencies": { "core-js-pure": "^3.25.1", @@ -166,6 +157,18 @@ "node": ">=6.9.0" } }, + "node_modules/@chevrotain/types": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-9.1.0.tgz", + "integrity": "sha512-3hbCD1CThkv9gnaSIPq0GUXwKni68e0ph6jIHwCvcWiQ4JB2xi8bFxBain0RF04qHUWuDjgnZLj4rLgimuGO+g==", + "dev": true + }, + "node_modules/@chevrotain/utils": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-9.1.0.tgz", + "integrity": "sha512-llLJZ8OAlZrjGlBvamm6Zdo/HmGAcCLq5gx7cSwUX8No+n/8ip+oaC4x33IdZIif8+Rh5dQUIZXmfbSghiOmNQ==", + "dev": true + }, "node_modules/@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -501,11 +504,44 @@ "tslib": "^2.4.0" } }, + "node_modules/@ts-morph/common": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.17.0.tgz", + "integrity": "sha512-RMSSvSfs9kb0VzkvQ2NWobwnj7TxCA9vI/IjR9bDHqgAyVbu2T0DN4wiKVqomyDWqO7dPr/tErSfq7urQ1Q37g==", + "dev": true, + "dependencies": { + "fast-glob": "^3.2.11", + "minimatch": "^5.1.0", + "mkdirp": "^1.0.4", + "path-browserify": "^1.0.1" + } + }, + "node_modules/@ts-morph/common/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@ts-morph/common/node_modules/minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@types/bcryptjs": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", - "dev": true + "peer": true }, "node_modules/@types/json5": { "version": "0.0.29", @@ -514,9 +550,9 @@ "dev": true }, "node_modules/@types/node": { - "version": "14.18.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.31.tgz", - "integrity": "sha512-vQAnaReSQkEDa8uwAyQby8bYGKu84R/deEc6mg5T8fX6gzCn8QW6rziSgsti1fNvsrswKUKPnVTi7uoB+u62Mw==", + "version": "14.18.32", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.32.tgz", + "integrity": "sha512-Y6S38pFr04yb13qqHf8uk1nHE3lXgQ30WZbv1mLliV9pt0NjvqdWttLcrOYLnXbOafknVYRHZGoMSpR9UwfYow==", "dev": true }, "node_modules/@types/prop-types": { @@ -552,14 +588,14 @@ "dev": true }, "node_modules/@typescript-eslint/parser": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.39.0.tgz", - "integrity": "sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.0.tgz", + "integrity": "sha512-Ah5gqyX2ySkiuYeOIDg7ap51/b63QgWZA7w6AHtFrag7aH0lRQPbLzUjk0c9o5/KZ6JRkTTDKShL4AUrQa6/hw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/typescript-estree": "5.39.0", + "@typescript-eslint/scope-manager": "5.40.0", + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/typescript-estree": "5.40.0", "debug": "^4.3.4" }, "engines": { @@ -579,13 +615,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.39.0.tgz", - "integrity": "sha512-/I13vAqmG3dyqMVSZPjsbuNQlYS082Y7OMkwhCfLXYsmlI0ca4nkL7wJ/4gjX70LD4P8Hnw1JywUVVAwepURBw==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.0.tgz", + "integrity": "sha512-d3nPmjUeZtEWRvyReMI4I1MwPGC63E8pDoHy0BnrYjnJgilBD3hv7XOiETKLY/zTwI7kCnBDf2vWTRUVpYw0Uw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/visitor-keys": "5.39.0" + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/visitor-keys": "5.40.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -596,9 +632,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.39.0.tgz", - "integrity": "sha512-gQMZrnfEBFXK38hYqt8Lkwt8f4U6yq+2H5VDSgP/qiTzC8Nw8JO3OuSUOQ2qW37S/dlwdkHDntkZM6SQhKyPhw==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.0.tgz", + "integrity": "sha512-V1KdQRTXsYpf1Y1fXCeZ+uhjW48Niiw0VGt4V8yzuaDTU8Z1Xl7yQDyQNqyAFcVhpYXIVCEuxSIWTsLDpHgTbw==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -609,13 +645,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.39.0.tgz", - "integrity": "sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.0.tgz", + "integrity": "sha512-b0GYlDj8TLTOqwX7EGbw2gL5EXS2CPEWhF9nGJiGmEcmlpNBjyHsTwbqpyIEPVpl6br4UcBOYlcI2FJVtJkYhg==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/visitor-keys": "5.39.0", + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/visitor-keys": "5.40.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -636,12 +672,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.39.0.tgz", - "integrity": "sha512-yyE3RPwOG+XJBLrhvsxAidUgybJVQ/hG8BhiJo0k8JSAYfk/CshVcxf0HwP4Jt7WZZ6vLmxdo1p6EyN3tzFTkg==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.0.tgz", + "integrity": "sha512-ijJ+6yig+x9XplEpG2K6FUdJeQGGj/15U3S56W9IqXKJqleuD7zJ2AX/miLezwxpd7ZxDAqO87zWufKg+RPZyQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "5.39.0", + "@typescript-eslint/types": "5.40.0", "eslint-visitor-keys": "^3.3.0" }, "engines": { @@ -661,15 +697,10 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@zenstackhq/generated": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/@zenstackhq/generated/-/generated-0.1.7.tgz", - "integrity": "sha512-KhR5vTU2R1a2MCkl8P91VjrnlnLTcsWI0O5gGO+H9TAlebR89m+4hc1Urat0gYyWNTzDGmnIXS1vwOf+ufRzow==" - }, - "node_modules/@zenstackhq/runtime": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@zenstackhq/runtime/-/runtime-0.1.3.tgz", - "integrity": "sha512-uOy9YsqbTQWAdzE59FuwuihfcgQeImUqXsmVl/J6XntRpVDzuLYalK3FczaIVr7gJp1jsuR0TvO2HfskGNOKHw==", + "node_modules/@zenstackhq/internal": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@zenstackhq/internal/-/internal-0.1.6.tgz", + "integrity": "sha512-E2iPDgih6StV+RioV0NWiLC6/m9i90CYs5t2dHSygKj2614+8oxcvf8OzQGOgtgEm12HaqRJHwonZWIo+NV3ag==", "dependencies": { "deepcopy": "^2.1.0", "swr": "^1.3.0" @@ -680,6 +711,16 @@ "react-dom": "^17.0.2 || ^18" } }, + "node_modules/@zenstackhq/runtime": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@zenstackhq/runtime/-/runtime-0.1.17.tgz", + "integrity": "sha512-7wzHGJYjWsvH2njYruZVLrWk6TpLZKYOEjzS/MAxoN0HdIHaQ7DISWfgWQdmSBaWSQoR1qvA1A7A+AhxvahZnA==", + "peerDependencies": { + "@types/bcryptjs": "^2.4.2", + "@zenstackhq/internal": "^0.1.0", + "bcryptjs": "^2.4.3" + } + }, "node_modules/acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -941,7 +982,8 @@ "node_modules/bcryptjs": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", + "peer": true }, "node_modules/binary-extensions": { "version": "2.2.0", @@ -1021,6 +1063,16 @@ "node": ">=6" } }, + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "dependencies": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, "node_modules/camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", @@ -1030,9 +1082,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001415", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001415.tgz", - "integrity": "sha512-ER+PfgCJUe8BqunLGWd/1EY4g8AzQcsDAVzdtMGKVtQEmKAwaFfU6vb7EAVIqTMYsqxBorYZi2+22Iouj/y7GQ==", + "version": "1.0.30001418", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", + "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==", "funding": [ { "type": "opencollective", @@ -1044,6 +1096,17 @@ } ] }, + "node_modules/capital-case": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", + "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -1060,6 +1123,37 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/change-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", + "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", + "dev": true, + "dependencies": { + "camel-case": "^4.1.2", + "capital-case": "^1.0.4", + "constant-case": "^3.0.4", + "dot-case": "^3.0.4", + "header-case": "^2.0.4", + "no-case": "^3.0.4", + "param-case": "^3.0.4", + "pascal-case": "^3.1.2", + "path-case": "^3.0.4", + "sentence-case": "^3.0.4", + "snake-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/chevrotain": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-9.1.0.tgz", + "integrity": "sha512-A86/55so63HCfu0dgGg3j9u8uuuBOrSqly1OhBZxRu2x6sAKILLzfVjbGMw45kgier6lz45EzcjjWtTRgoT84Q==", + "dev": true, + "dependencies": { + "@chevrotain/types": "^9.1.0", + "@chevrotain/utils": "^9.1.0", + "regexp-to-ast": "0.5.0" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -1086,6 +1180,12 @@ "fsevents": "~2.3.2" } }, + "node_modules/code-block-writer": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-11.0.3.tgz", + "integrity": "sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==", + "dev": true + }, "node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -1123,12 +1223,41 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "node_modules/constant-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", + "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case": "^2.0.2" + } + }, "node_modules/cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -1257,9 +1386,12 @@ } }, "node_modules/defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/detective": { "version": "5.2.1", @@ -1311,10 +1443,20 @@ "node": ">=6.0.0" } }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/electron-to-chromium": { - "version": "1.4.271", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.271.tgz", - "integrity": "sha512-BCPBtK07xR1/uY2HFDtl3wK2De66AW4MSiPlLrnPNxKC/Qhccxd59W73654S3y6Rb/k3hmuGJOBnhjfoutetXA==" + "version": "1.4.281", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.281.tgz", + "integrity": "sha512-yer0w5wCYdFoZytfmbNhwiGI/3cW06+RV7E23ln4490DVMxs7PvYpbsrSmAiBn/V6gode8wvJlST2YfWgvzWIg==" }, "node_modules/emoji-regex": { "version": "9.2.2", @@ -1335,9 +1477,9 @@ } }, "node_modules/es-abstract": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.3.tgz", - "integrity": "sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "dependencies": { "call-bind": "^1.0.2", @@ -1350,7 +1492,7 @@ "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.6", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", @@ -1677,9 +1819,9 @@ } }, "node_modules/eslint-plugin-react": { - "version": "7.31.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", - "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==", + "version": "7.31.10", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz", + "integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==", "dev": true, "dependencies": { "array-includes": "^3.1.5", @@ -2217,6 +2359,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/header-case": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", + "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", + "dev": true, + "dependencies": { + "capital-case": "^1.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -2565,6 +2717,21 @@ "node": ">=4.0" } }, + "node_modules/langium": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/langium/-/langium-0.4.0.tgz", + "integrity": "sha512-VDwbcSdd4Uzektou73gcuqSt1eJcizHWJic7ZGIkTQyBIiRTP66YvMlxLUUE9T9p4/lCZGwf9D8CCBc7RiXZ7A==", + "dev": true, + "dependencies": { + "chevrotain": "^9.1.0", + "vscode-languageserver": "^7.0.0", + "vscode-languageserver-textdocument": "^1.0.1", + "vscode-uri": "^3.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -2624,6 +2791,15 @@ "loose-envify": "cli.js" } }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -2668,9 +2844,24 @@ } }, "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } }, "node_modules/ms": { "version": "2.1.2", @@ -2748,9 +2939,9 @@ } }, "node_modules/next-auth": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.12.2.tgz", - "integrity": "sha512-B25iFUIKYa2pRMWRFPIQWv84WJydqIsv6EbriNuzqNSZnxnlmpsrmJrTeMMLf+9a3qf9FG8enxDmDntmwnBkDQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.13.0.tgz", + "integrity": "sha512-FtkPpeb9Bax6yKDaxcaGIvZZjvr10JaU2AsBYv1yv4N6rP86Xa7/4Ro1Aq94YGwsYzk+YKS52CRjD2DqCcSmVA==", "dependencies": { "@babel/runtime": "^7.16.3", "@panva/hkdf": "^1.0.1", @@ -2800,6 +2991,16 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node_modules/node-releases": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", @@ -2988,6 +3189,16 @@ "node": ">= 0.8.0" } }, + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -3000,6 +3211,32 @@ "node": ">=6" } }, + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "node_modules/path-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", + "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -3057,9 +3294,9 @@ } }, "node_modules/postcss": { - "version": "8.4.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz", - "integrity": "sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==", + "version": "8.4.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", + "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", "funding": [ { "type": "opencollective", @@ -3177,18 +3414,18 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "node_modules/preact": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.0.tgz", - "integrity": "sha512-Fk6+vB2kb6mSJfDgODq0YDhMfl0HNtK5+Uc9QqECO4nlyPAQwCI+BKyWO//idA7ikV7o+0Fm6LQmNuQi1wXI1w==", + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.1.tgz", + "integrity": "sha512-1Wz5PCRm6Fg+6BTXWJHhX4wRK9MZbZBHuwBqfZlOdVm2NqPe8/rjYpufvYCwJSGb9layyzB2jTTXfpCTynLqFQ==", "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" } }, "node_modules/preact-render-to-string": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.4.tgz", - "integrity": "sha512-iIPHb3BXUQ3Za6KNhkjN/waq11Oh+QWWtAgN3id3LrL+cszH3DYh8TxJPNQ6Aogsbu4JsqdJLBZltwPFpG6N6w==", + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.5.tgz", + "integrity": "sha512-rEBn42C3Wh+AjPxXUbDkb6xw0cTJQgxdYlp6ytUR1uBZF647Wn6ykkopMeQlRl7ggX+qnYYjZ4Hs1abZENl7ww==", "dependencies": { "pretty-format": "^3.8.0" }, @@ -3236,6 +3473,15 @@ "node": ">=0.4.0" } }, + "node_modules/promisify": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/promisify/-/promisify-0.0.3.tgz", + "integrity": "sha512-CcBGsRhhq466fsZVyHfptuKqon6eih0CqMsJE0kWIIjbpVNEyDoaKLELm2WVs//W/WXRBHip+6xhTExTkHUwtA==", + "dev": true, + "dependencies": { + "when": "" + } + }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -3339,6 +3585,12 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, + "node_modules/regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", + "dev": true + }, "node_modules/regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -3471,9 +3723,9 @@ } }, "node_modules/semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -3485,6 +3737,17 @@ "node": ">=10" } }, + "node_modules/sentence-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", + "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", + "dev": true, + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -3554,6 +3817,16 @@ "url": "https://github.com/chalk/slice-ansi?sponsor=1" } }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "node_modules/source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -3831,6 +4104,16 @@ "node": ">=8.0" } }, + "node_modules/ts-morph": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-16.0.0.tgz", + "integrity": "sha512-jGNF0GVpFj0orFw55LTsQxVYEUOCWBAbR5Ls7fTYE5pQsbW18ssTb/6UXx/GYAEjS+DQTp8VoTw0vqYMiaaQuw==", + "dev": true, + "dependencies": { + "@ts-morph/common": "~0.17.0", + "code-block-writer": "^11.0.3" + } + }, "node_modules/tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -3930,9 +4213,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "funding": [ { "type": "opencollective", @@ -3954,6 +4237,24 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/upper-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", + "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/upper-case-first": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", + "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", + "dev": true, + "dependencies": { + "tslib": "^2.0.3" + } + }, "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -3990,6 +4291,84 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "node_modules/vscode-jsonrpc": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz", + "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageclient": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.0.0.tgz", + "integrity": "sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg==", + "dev": true, + "dependencies": { + "minimatch": "^3.0.4", + "semver": "^7.3.4", + "vscode-languageserver-protocol": "3.16.0" + }, + "engines": { + "vscode": "^1.52.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz", + "integrity": "sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw==", + "dev": true, + "dependencies": { + "vscode-languageserver-protocol": "3.16.0" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz", + "integrity": "sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==", + "dev": true, + "dependencies": { + "vscode-jsonrpc": "6.0.0", + "vscode-languageserver-types": "3.16.0" + } + }, + "node_modules/vscode-languageserver-protocol/node_modules/vscode-jsonrpc": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz", + "integrity": "sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==", + "dev": true, + "engines": { + "node": ">=8.0.0 || >=10.0.0" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz", + "integrity": "sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg==", + "dev": true + }, + "node_modules/vscode-languageserver-types": { + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz", + "integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==", + "dev": true + }, + "node_modules/vscode-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.6.tgz", + "integrity": "sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ==", + "dev": true + }, + "node_modules/when": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha512-5cZ7mecD3eYcMiCH4wtRPA5iFJZ50BJYDfckI5RRpQiktMiYTcn0ccLTZOvcbBume+1304fQztxeNzNS9Gvrnw==", + "dev": true + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4056,6 +4435,33 @@ "engines": { "node": ">= 6" } + }, + "node_modules/zenstack": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/zenstack/-/zenstack-0.1.19.tgz", + "integrity": "sha512-4sJju87k+5UrXBPqH854iRm4RimQM0IwA1wOoUOltHxD8K9g2qrKC3/DH+d9mSMwbZZ4wvrRdg879g3YJcXfrA==", + "dev": true, + "dependencies": { + "@zenstackhq/internal": "0.1.6", + "change-case": "^4.1.2", + "chevrotain": "^9.1.0", + "colors": "^1.4.0", + "commander": "^8.0.0", + "langium": "^0.4.0", + "prisma": "^4.4.0", + "promisify": "^0.0.3", + "ts-morph": "^16.0.0", + "vscode-jsonrpc": "^8.0.2", + "vscode-languageclient": "^7.0.0", + "vscode-languageserver": "^7.0.0", + "vscode-uri": "^3.0.2" + }, + "bin": { + "zenstack": "bin/cli" + }, + "engines": { + "vscode": "^1.56.0" + } } }, "dependencies": { @@ -4144,23 +4550,35 @@ } }, "@babel/runtime": { - "version": "7.19.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.0.tgz", - "integrity": "sha512-eR8Lo9hnDS7tqkO7NsV+mKvCmv5boaXFSZ70DnfhcgiEne8hv9oCEd36Klw74EtizEqLsy4YnW8UWwpBVolHZA==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz", + "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==", "requires": { "regenerator-runtime": "^0.13.4" } }, "@babel/runtime-corejs3": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.1.tgz", - "integrity": "sha512-j2vJGnkopRzH+ykJ8h68wrHnEUmtK//E723jjixiAl/PPf6FhqY/vYRcMVlNydRKQjQsTsYEjpx+DZMIvnGk/g==", + "version": "7.19.4", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs3/-/runtime-corejs3-7.19.4.tgz", + "integrity": "sha512-HzjQ8+dzdx7dmZy4DQ8KV8aHi/74AjEbBGTFutBmg/pd3dY5/q1sfuOGPTFGEytlQhWoeVXqcK5BwMgIkRkNDQ==", "dev": true, "requires": { "core-js-pure": "^3.25.1", "regenerator-runtime": "^0.13.4" } }, + "@chevrotain/types": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-9.1.0.tgz", + "integrity": "sha512-3hbCD1CThkv9gnaSIPq0GUXwKni68e0ph6jIHwCvcWiQ4JB2xi8bFxBain0RF04qHUWuDjgnZLj4rLgimuGO+g==", + "dev": true + }, + "@chevrotain/utils": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@chevrotain/utils/-/utils-9.1.0.tgz", + "integrity": "sha512-llLJZ8OAlZrjGlBvamm6Zdo/HmGAcCLq5gx7cSwUX8No+n/8ip+oaC4x33IdZIif8+Rh5dQUIZXmfbSghiOmNQ==", + "dev": true + }, "@eslint/eslintrc": { "version": "0.4.3", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.3.tgz", @@ -4348,11 +4766,43 @@ "tslib": "^2.4.0" } }, + "@ts-morph/common": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.17.0.tgz", + "integrity": "sha512-RMSSvSfs9kb0VzkvQ2NWobwnj7TxCA9vI/IjR9bDHqgAyVbu2T0DN4wiKVqomyDWqO7dPr/tErSfq7urQ1Q37g==", + "dev": true, + "requires": { + "fast-glob": "^3.2.11", + "minimatch": "^5.1.0", + "mkdirp": "^1.0.4", + "path-browserify": "^1.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz", + "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, "@types/bcryptjs": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@types/bcryptjs/-/bcryptjs-2.4.2.tgz", "integrity": "sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==", - "dev": true + "peer": true }, "@types/json5": { "version": "0.0.29", @@ -4361,9 +4811,9 @@ "dev": true }, "@types/node": { - "version": "14.18.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.31.tgz", - "integrity": "sha512-vQAnaReSQkEDa8uwAyQby8bYGKu84R/deEc6mg5T8fX6gzCn8QW6rziSgsti1fNvsrswKUKPnVTi7uoB+u62Mw==", + "version": "14.18.32", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.32.tgz", + "integrity": "sha512-Y6S38pFr04yb13qqHf8uk1nHE3lXgQ30WZbv1mLliV9pt0NjvqdWttLcrOYLnXbOafknVYRHZGoMSpR9UwfYow==", "dev": true }, "@types/prop-types": { @@ -4399,41 +4849,41 @@ "dev": true }, "@typescript-eslint/parser": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.39.0.tgz", - "integrity": "sha512-PhxLjrZnHShe431sBAGHaNe6BDdxAASDySgsBCGxcBecVCi8NQWxQZMcizNA4g0pN51bBAn/FUfkWG3SDVcGlA==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.40.0.tgz", + "integrity": "sha512-Ah5gqyX2ySkiuYeOIDg7ap51/b63QgWZA7w6AHtFrag7aH0lRQPbLzUjk0c9o5/KZ6JRkTTDKShL4AUrQa6/hw==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "5.39.0", - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/typescript-estree": "5.39.0", + "@typescript-eslint/scope-manager": "5.40.0", + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/typescript-estree": "5.40.0", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.39.0.tgz", - "integrity": "sha512-/I13vAqmG3dyqMVSZPjsbuNQlYS082Y7OMkwhCfLXYsmlI0ca4nkL7wJ/4gjX70LD4P8Hnw1JywUVVAwepURBw==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.40.0.tgz", + "integrity": "sha512-d3nPmjUeZtEWRvyReMI4I1MwPGC63E8pDoHy0BnrYjnJgilBD3hv7XOiETKLY/zTwI7kCnBDf2vWTRUVpYw0Uw==", "dev": true, "requires": { - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/visitor-keys": "5.39.0" + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/visitor-keys": "5.40.0" } }, "@typescript-eslint/types": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.39.0.tgz", - "integrity": "sha512-gQMZrnfEBFXK38hYqt8Lkwt8f4U6yq+2H5VDSgP/qiTzC8Nw8JO3OuSUOQ2qW37S/dlwdkHDntkZM6SQhKyPhw==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.40.0.tgz", + "integrity": "sha512-V1KdQRTXsYpf1Y1fXCeZ+uhjW48Niiw0VGt4V8yzuaDTU8Z1Xl7yQDyQNqyAFcVhpYXIVCEuxSIWTsLDpHgTbw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.39.0.tgz", - "integrity": "sha512-qLFQP0f398sdnogJoLtd43pUgB18Q50QSA+BTE5h3sUxySzbWDpTSdgt4UyxNSozY/oDK2ta6HVAzvGgq8JYnA==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.40.0.tgz", + "integrity": "sha512-b0GYlDj8TLTOqwX7EGbw2gL5EXS2CPEWhF9nGJiGmEcmlpNBjyHsTwbqpyIEPVpl6br4UcBOYlcI2FJVtJkYhg==", "dev": true, "requires": { - "@typescript-eslint/types": "5.39.0", - "@typescript-eslint/visitor-keys": "5.39.0", + "@typescript-eslint/types": "5.40.0", + "@typescript-eslint/visitor-keys": "5.40.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -4442,12 +4892,12 @@ } }, "@typescript-eslint/visitor-keys": { - "version": "5.39.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.39.0.tgz", - "integrity": "sha512-yyE3RPwOG+XJBLrhvsxAidUgybJVQ/hG8BhiJo0k8JSAYfk/CshVcxf0HwP4Jt7WZZ6vLmxdo1p6EyN3tzFTkg==", + "version": "5.40.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.40.0.tgz", + "integrity": "sha512-ijJ+6yig+x9XplEpG2K6FUdJeQGGj/15U3S56W9IqXKJqleuD7zJ2AX/miLezwxpd7ZxDAqO87zWufKg+RPZyQ==", "dev": true, "requires": { - "@typescript-eslint/types": "5.39.0", + "@typescript-eslint/types": "5.40.0", "eslint-visitor-keys": "^3.3.0" }, "dependencies": { @@ -4459,20 +4909,21 @@ } } }, - "@zenstackhq/generated": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/@zenstackhq/generated/-/generated-0.1.7.tgz", - "integrity": "sha512-KhR5vTU2R1a2MCkl8P91VjrnlnLTcsWI0O5gGO+H9TAlebR89m+4hc1Urat0gYyWNTzDGmnIXS1vwOf+ufRzow==" - }, - "@zenstackhq/runtime": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@zenstackhq/runtime/-/runtime-0.1.3.tgz", - "integrity": "sha512-uOy9YsqbTQWAdzE59FuwuihfcgQeImUqXsmVl/J6XntRpVDzuLYalK3FczaIVr7gJp1jsuR0TvO2HfskGNOKHw==", + "@zenstackhq/internal": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@zenstackhq/internal/-/internal-0.1.6.tgz", + "integrity": "sha512-E2iPDgih6StV+RioV0NWiLC6/m9i90CYs5t2dHSygKj2614+8oxcvf8OzQGOgtgEm12HaqRJHwonZWIo+NV3ag==", "requires": { "deepcopy": "^2.1.0", "swr": "^1.3.0" } }, + "@zenstackhq/runtime": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/@zenstackhq/runtime/-/runtime-0.1.17.tgz", + "integrity": "sha512-7wzHGJYjWsvH2njYruZVLrWk6TpLZKYOEjzS/MAxoN0HdIHaQ7DISWfgWQdmSBaWSQoR1qvA1A7A+AhxvahZnA==", + "requires": {} + }, "acorn": { "version": "7.4.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", @@ -4655,7 +5106,8 @@ "bcryptjs": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==" + "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", + "peer": true }, "binary-extensions": { "version": "2.2.0", @@ -4707,15 +5159,36 @@ "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "dev": true, + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" + } + }, "camelcase-css": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==" }, "caniuse-lite": { - "version": "1.0.30001415", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001415.tgz", - "integrity": "sha512-ER+PfgCJUe8BqunLGWd/1EY4g8AzQcsDAVzdtMGKVtQEmKAwaFfU6vb7EAVIqTMYsqxBorYZi2+22Iouj/y7GQ==" + "version": "1.0.30001418", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001418.tgz", + "integrity": "sha512-oIs7+JL3K9JRQ3jPZjlH6qyYDp+nBTCais7hjh0s+fuBwufc7uZ7hPYMXrDOJhV360KGMTcczMRObk0/iMqZRg==" + }, + "capital-case": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.4.tgz", + "integrity": "sha512-ds37W8CytHgwnhGGTi88pcPyR15qoNkOpYwmMMfnWqqWgESapLqvDx6huFjQ5vqWSn2Z06173XNA7LtMOeUh1A==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } }, "chalk": { "version": "4.1.2", @@ -4727,6 +5200,37 @@ "supports-color": "^7.1.0" } }, + "change-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.2.tgz", + "integrity": "sha512-bSxY2ws9OtviILG1EiY5K7NNxkqg/JnRnFxLtKQ96JaviiIxi7djMrSd0ECT9AC+lttClmYwKw53BWpOMblo7A==", + "dev": true, + "requires": { + "camel-case": "^4.1.2", + "capital-case": "^1.0.4", + "constant-case": "^3.0.4", + "dot-case": "^3.0.4", + "header-case": "^2.0.4", + "no-case": "^3.0.4", + "param-case": "^3.0.4", + "pascal-case": "^3.1.2", + "path-case": "^3.0.4", + "sentence-case": "^3.0.4", + "snake-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "chevrotain": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/chevrotain/-/chevrotain-9.1.0.tgz", + "integrity": "sha512-A86/55so63HCfu0dgGg3j9u8uuuBOrSqly1OhBZxRu2x6sAKILLzfVjbGMw45kgier6lz45EzcjjWtTRgoT84Q==", + "dev": true, + "requires": { + "@chevrotain/types": "^9.1.0", + "@chevrotain/utils": "^9.1.0", + "regexp-to-ast": "0.5.0" + } + }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -4742,6 +5246,12 @@ "readdirp": "~3.6.0" } }, + "code-block-writer": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-11.0.3.tgz", + "integrity": "sha512-NiujjUFB4SwScJq2bwbYUtXbZhBSlY6vYzm++3Q6oC+U+injTqfPYFK8wS9COOmb2lueqp0ZRB4nK1VYeHgNyw==", + "dev": true + }, "color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -4773,12 +5283,35 @@ "simple-swizzle": "^0.2.2" } }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, + "constant-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.4.tgz", + "integrity": "sha512-I2hSBi7Vvs7BEuJDr5dDHfzb/Ruj3FyvFyh7KLilAjNQw3Be+xgqUBA2W6scVEcL0hL1dwPRtIqEPVUCKkSsyQ==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case": "^2.0.2" + } + }, "cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -4872,9 +5405,9 @@ } }, "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==" + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz", + "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==" }, "detective": { "version": "5.2.1", @@ -4914,10 +5447,20 @@ "esutils": "^2.0.2" } }, + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "electron-to-chromium": { - "version": "1.4.271", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.271.tgz", - "integrity": "sha512-BCPBtK07xR1/uY2HFDtl3wK2De66AW4MSiPlLrnPNxKC/Qhccxd59W73654S3y6Rb/k3hmuGJOBnhjfoutetXA==" + "version": "1.4.281", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.281.tgz", + "integrity": "sha512-yer0w5wCYdFoZytfmbNhwiGI/3cW06+RV7E23ln4490DVMxs7PvYpbsrSmAiBn/V6gode8wvJlST2YfWgvzWIg==" }, "emoji-regex": { "version": "9.2.2", @@ -4935,9 +5478,9 @@ } }, "es-abstract": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.3.tgz", - "integrity": "sha512-AyrnaKVpMzljIdwjzrj+LxGmj8ik2LckwXacHqrJJ/jxz6dDDBcZ7I7nlHM0FvEW8MfbWJwOd+yT2XzYW49Frw==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.20.4.tgz", + "integrity": "sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==", "dev": true, "requires": { "call-bind": "^1.0.2", @@ -4950,7 +5493,7 @@ "has-property-descriptors": "^1.0.0", "has-symbols": "^1.0.3", "internal-slot": "^1.0.3", - "is-callable": "^1.2.6", + "is-callable": "^1.2.7", "is-negative-zero": "^2.0.2", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", @@ -5209,9 +5752,9 @@ } }, "eslint-plugin-react": { - "version": "7.31.8", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.8.tgz", - "integrity": "sha512-5lBTZmgQmARLLSYiwI71tiGVTLUuqXantZM6vlSY39OaDSV0M7+32K5DnLkmFrwTe+Ksz0ffuLUC91RUviVZfw==", + "version": "7.31.10", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.31.10.tgz", + "integrity": "sha512-e4N/nc6AAlg4UKW/mXeYWd3R++qUano5/o+t+wnWxIf+bLsOaH3a4q74kX3nDjYym3VBN4HyO9nEn1GcAqgQOA==", "dev": true, "requires": { "array-includes": "^3.1.5", @@ -5601,6 +6144,16 @@ "has-symbols": "^1.0.2" } }, + "header-case": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.4.tgz", + "integrity": "sha512-H/vuk5TEEVZwrR0lp2zed9OCo1uAILMlx0JEMgC26rzyJJ3N1v6XkwHHXJQdR2doSjcGPM6OKPYoJgf0plJ11Q==", + "dev": true, + "requires": { + "capital-case": "^1.0.4", + "tslib": "^2.0.3" + } + }, "ignore": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", @@ -5847,6 +6400,18 @@ "object.assign": "^4.1.3" } }, + "langium": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/langium/-/langium-0.4.0.tgz", + "integrity": "sha512-VDwbcSdd4Uzektou73gcuqSt1eJcizHWJic7ZGIkTQyBIiRTP66YvMlxLUUE9T9p4/lCZGwf9D8CCBc7RiXZ7A==", + "dev": true, + "requires": { + "chevrotain": "^9.1.0", + "vscode-languageserver": "^7.0.0", + "vscode-languageserver-textdocument": "^1.0.1", + "vscode-uri": "^3.0.2" + } + }, "language-subtag-registry": { "version": "0.3.22", "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", @@ -5897,6 +6462,15 @@ "js-tokens": "^3.0.0 || ^4.0.0" } }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -5929,9 +6503,15 @@ } }, "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", + "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true }, "ms": { "version": "2.1.2", @@ -5989,9 +6569,9 @@ } }, "next-auth": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.12.2.tgz", - "integrity": "sha512-B25iFUIKYa2pRMWRFPIQWv84WJydqIsv6EbriNuzqNSZnxnlmpsrmJrTeMMLf+9a3qf9FG8enxDmDntmwnBkDQ==", + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-4.13.0.tgz", + "integrity": "sha512-FtkPpeb9Bax6yKDaxcaGIvZZjvr10JaU2AsBYv1yv4N6rP86Xa7/4Ro1Aq94YGwsYzk+YKS52CRjD2DqCcSmVA==", "requires": { "@babel/runtime": "^7.16.3", "@panva/hkdf": "^1.0.1", @@ -6004,6 +6584,16 @@ "uuid": "^8.3.2" } }, + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "dev": true, + "requires": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, "node-releases": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.6.tgz", @@ -6141,6 +6731,16 @@ "word-wrap": "^1.2.3" } }, + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -6150,6 +6750,32 @@ "callsites": "^3.0.0" } }, + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true + }, + "path-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.4.tgz", + "integrity": "sha512-qO4qCFjXqVTrcbPt/hQfhTQ+VhFsqNKOPtytgNKkKxSoEp3XPUQ8ObFuePylOIok5gjn69ry8XiULxCwot3Wfg==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -6189,9 +6815,9 @@ "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==" }, "postcss": { - "version": "8.4.17", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.17.tgz", - "integrity": "sha512-UNxNOLQydcOFi41yHNMcKRZ39NeXlr8AxGuZJsdub8vIb12fHzcq37DTU/QtbI6WLxNg2gF9Z+8qtRwTj1UI1Q==", + "version": "8.4.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.18.tgz", + "integrity": "sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==", "requires": { "nanoid": "^3.3.4", "picocolors": "^1.0.0", @@ -6248,14 +6874,14 @@ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" }, "preact": { - "version": "10.11.0", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.0.tgz", - "integrity": "sha512-Fk6+vB2kb6mSJfDgODq0YDhMfl0HNtK5+Uc9QqECO4nlyPAQwCI+BKyWO//idA7ikV7o+0Fm6LQmNuQi1wXI1w==" + "version": "10.11.1", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.11.1.tgz", + "integrity": "sha512-1Wz5PCRm6Fg+6BTXWJHhX4wRK9MZbZBHuwBqfZlOdVm2NqPe8/rjYpufvYCwJSGb9layyzB2jTTXfpCTynLqFQ==" }, "preact-render-to-string": { - "version": "5.2.4", - "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.4.tgz", - "integrity": "sha512-iIPHb3BXUQ3Za6KNhkjN/waq11Oh+QWWtAgN3id3LrL+cszH3DYh8TxJPNQ6Aogsbu4JsqdJLBZltwPFpG6N6w==", + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.2.5.tgz", + "integrity": "sha512-rEBn42C3Wh+AjPxXUbDkb6xw0cTJQgxdYlp6ytUR1uBZF647Wn6ykkopMeQlRl7ggX+qnYYjZ4Hs1abZENl7ww==", "requires": { "pretty-format": "^3.8.0" } @@ -6286,6 +6912,15 @@ "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", "dev": true }, + "promisify": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/promisify/-/promisify-0.0.3.tgz", + "integrity": "sha512-CcBGsRhhq466fsZVyHfptuKqon6eih0CqMsJE0kWIIjbpVNEyDoaKLELm2WVs//W/WXRBHip+6xhTExTkHUwtA==", + "dev": true, + "requires": { + "when": "" + } + }, "prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -6357,6 +6992,12 @@ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" }, + "regexp-to-ast": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.5.0.tgz", + "integrity": "sha512-tlbJqcMHnPKI9zSrystikWKwHkBqu2a/Sgw01h3zFjvYrMxEDYHzzoMZnUrbIfpTFEsoRnnviOXNCzFiSc54Qw==", + "dev": true + }, "regexp.prototype.flags": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.3.tgz", @@ -6438,14 +7079,25 @@ } }, "semver": { - "version": "7.3.7", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", - "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "version": "7.3.8", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", + "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", "dev": true, "requires": { "lru-cache": "^6.0.0" } }, + "sentence-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.4.tgz", + "integrity": "sha512-8LS0JInaQMCRoQ7YUytAo/xUu5W2XnQxV2HI/6uM6U7CITS1RqPElr30V6uIqyMKM9lJGRVFy5/4CuzcixNYSg==", + "dev": true, + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3", + "upper-case-first": "^2.0.2" + } + }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6497,6 +7149,16 @@ "is-fullwidth-code-point": "^3.0.0" } }, + "snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, "source-map-js": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", @@ -6703,6 +7365,16 @@ "is-number": "^7.0.0" } }, + "ts-morph": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/ts-morph/-/ts-morph-16.0.0.tgz", + "integrity": "sha512-jGNF0GVpFj0orFw55LTsQxVYEUOCWBAbR5Ls7fTYE5pQsbW18ssTb/6UXx/GYAEjS+DQTp8VoTw0vqYMiaaQuw==", + "dev": true, + "requires": { + "@ts-morph/common": "~0.17.0", + "code-block-writer": "^11.0.3" + } + }, "tsconfig-paths": { "version": "3.14.1", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz", @@ -6776,14 +7448,32 @@ } }, "update-browserslist-db": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.9.tgz", - "integrity": "sha512-/xsqn21EGVdXI3EXSum1Yckj3ZVZugqyOZQ/CxYPBD/R+ko9NSUScf8tFF4dOKY+2pvSSJA/S+5B8s4Zr4kyvg==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.10.tgz", + "integrity": "sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==", "requires": { "escalade": "^3.1.1", "picocolors": "^1.0.0" } }, + "upper-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.2.tgz", + "integrity": "sha512-KgdgDGJt2TpuwBUIjgG6lzw2GWFRCW9Qkfkiv0DxqHHLYJHmtmdUIKcZd8rHgFSjopVTlw6ggzCm1b8MFQwikg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } + }, + "upper-case-first": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.2.tgz", + "integrity": "sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==", + "dev": true, + "requires": { + "tslib": "^2.0.3" + } + }, "uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", @@ -6815,6 +7505,74 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, + "vscode-jsonrpc": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz", + "integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==", + "dev": true + }, + "vscode-languageclient": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-7.0.0.tgz", + "integrity": "sha512-P9AXdAPlsCgslpP9pRxYPqkNYV7Xq8300/aZDpO35j1fJm/ncize8iGswzYlcvFw5DQUx4eVk+KvfXdL0rehNg==", + "dev": true, + "requires": { + "minimatch": "^3.0.4", + "semver": "^7.3.4", + "vscode-languageserver-protocol": "3.16.0" + } + }, + "vscode-languageserver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-7.0.0.tgz", + "integrity": "sha512-60HTx5ID+fLRcgdHfmz0LDZAXYEV68fzwG0JWwEPBode9NuMYTIxuYXPg4ngO8i8+Ou0lM7y6GzaYWbiDL0drw==", + "dev": true, + "requires": { + "vscode-languageserver-protocol": "3.16.0" + } + }, + "vscode-languageserver-protocol": { + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.16.0.tgz", + "integrity": "sha512-sdeUoAawceQdgIfTI+sdcwkiK2KU+2cbEYA0agzM2uqaUy2UpnnGHtWTHVEtS0ES4zHU0eMFRGN+oQgDxlD66A==", + "dev": true, + "requires": { + "vscode-jsonrpc": "6.0.0", + "vscode-languageserver-types": "3.16.0" + }, + "dependencies": { + "vscode-jsonrpc": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-6.0.0.tgz", + "integrity": "sha512-wnJA4BnEjOSyFMvjZdpiOwhSq9uDoK8e/kpRJDTaMYzwlkrhG1fwDIZI94CLsLzlCK5cIbMMtFlJlfR57Lavmg==", + "dev": true + } + } + }, + "vscode-languageserver-textdocument": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.7.tgz", + "integrity": "sha512-bFJH7UQxlXT8kKeyiyu41r22jCZXG8kuuVVA33OEJn1diWOZK5n8zBSPZFHVBOu8kXZ6h0LIRhf5UnCo61J4Hg==", + "dev": true + }, + "vscode-languageserver-types": { + "version": "3.16.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.16.0.tgz", + "integrity": "sha512-k8luDIWJWyenLc5ToFQQMaSrqCHiLwyKPHKPQZ5zz21vM+vIVUSvsRpcbiECH4WR88K2XZqc4ScRcZ7nk/jbeA==", + "dev": true + }, + "vscode-uri": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.0.6.tgz", + "integrity": "sha512-fmL7V1eiDBFRRnu+gfRWTzyPpNIHJTc4mWnFkwBUmO9U3KPgJAmTx7oxi2bl/Rh6HLdU7+4C9wlj0k2E4AdKFQ==", + "dev": true + }, + "when": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/when/-/when-3.7.8.tgz", + "integrity": "sha512-5cZ7mecD3eYcMiCH4wtRPA5iFJZ50BJYDfckI5RRpQiktMiYTcn0ccLTZOvcbBume+1304fQztxeNzNS9Gvrnw==", + "dev": true + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -6863,6 +7621,27 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" + }, + "zenstack": { + "version": "0.1.19", + "resolved": "https://registry.npmjs.org/zenstack/-/zenstack-0.1.19.tgz", + "integrity": "sha512-4sJju87k+5UrXBPqH854iRm4RimQM0IwA1wOoUOltHxD8K9g2qrKC3/DH+d9mSMwbZZ4wvrRdg879g3YJcXfrA==", + "dev": true, + "requires": { + "@zenstackhq/internal": "0.1.6", + "change-case": "^4.1.2", + "chevrotain": "^9.1.0", + "colors": "^1.4.0", + "commander": "^8.0.0", + "langium": "^0.4.0", + "prisma": "^4.4.0", + "promisify": "^0.0.3", + "ts-morph": "^16.0.0", + "vscode-jsonrpc": "^8.0.2", + "vscode-languageclient": "^7.0.0", + "vscode-languageserver": "^7.0.0", + "vscode-uri": "^3.0.2" + } } } } diff --git a/samples/todo/package.json b/samples/todo/package.json index 0b342e1d3..f417bab70 100644 --- a/samples/todo/package.json +++ b/samples/todo/package.json @@ -11,13 +11,11 @@ "db-push": "prisma db push --schema .zenstack/schema.prisma", "db-migrate": "prisma migrate dev --schema .zenstack/schema.prisma", "db-reset": "prisma migrate reset --schema .zenstack/schema.prisma", - "generate": "node ../../packages/schema/bin/cli generate ./schema.zmodel" + "generate": "zenstack generate ./schema.zmodel" }, "dependencies": { "@prisma/client": "^4.4.0", - "@zenstackhq/generated": "latest", "@zenstackhq/runtime": "latest", - "bcryptjs": "^2.4.3", "daisyui": "^2.31.0", "next": "12.3.1", "next-auth": "^4.10.3", @@ -26,7 +24,6 @@ "swr": "^1.3.0" }, "devDependencies": { - "@types/bcryptjs": "^2.4.2", "@types/node": "^14.17.3", "@types/react": "18.0.21", "@types/react-dom": "18.0.6", @@ -34,8 +31,8 @@ "eslint": "^7.19.0", "eslint-config-next": "12.3.1", "postcss": "^8.4.16", - "prisma": "^4.4.0", "tailwindcss": "^3.1.8", - "typescript": "^4.6.2" + "typescript": "^4.6.2", + "zenstack": "latest" } } diff --git a/samples/todo/pages/api/auth/[...nextauth].ts b/samples/todo/pages/api/auth/[...nextauth].ts index 7c891a975..b0df63407 100644 --- a/samples/todo/pages/api/auth/[...nextauth].ts +++ b/samples/todo/pages/api/auth/[...nextauth].ts @@ -4,8 +4,8 @@ import GoogleProvider from 'next-auth/providers/google'; import { authorize, NextAuthAdapter as Adapter, -} from '@zenstackhq/generated/auth'; -import service from '@zenstackhq/generated'; +} from '@zenstackhq/runtime/auth'; +import service from '@zenstackhq/runtime'; export const authOptions: NextAuthOptions = { // Configure one or more authentication providers diff --git a/samples/todo/pages/api/hello.ts b/samples/todo/pages/api/hello.ts deleted file mode 100644 index f8bcc7e5c..000000000 --- a/samples/todo/pages/api/hello.ts +++ /dev/null @@ -1,13 +0,0 @@ -// Next.js API route support: https://nextjs.org/docs/api-routes/introduction -import type { NextApiRequest, NextApiResponse } from 'next' - -type Data = { - name: string -} - -export default function handler( - req: NextApiRequest, - res: NextApiResponse -) { - res.status(200).json({ name: 'John Doe' }) -} diff --git a/samples/todo/pages/api/zen/[...path].ts b/samples/todo/pages/api/zenstack/[...path].ts similarity index 74% rename from samples/todo/pages/api/zen/[...path].ts rename to samples/todo/pages/api/zenstack/[...path].ts index 8b83c3f2a..d078ed3e6 100644 --- a/samples/todo/pages/api/zen/[...path].ts +++ b/samples/todo/pages/api/zenstack/[...path].ts @@ -1,11 +1,11 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { type RequestHandlerOptions, - RequestHandler, -} from '@zenstackhq/runtime'; + requestHandler, +} from '@zenstackhq/runtime/server'; import { authOptions } from '@api/auth/[...nextauth]'; import { unstable_getServerSession } from 'next-auth'; -import service from '@zenstackhq/generated'; +import service from '@zenstackhq/runtime'; const options: RequestHandlerOptions = { async getServerUser(req: NextApiRequest, res: NextApiResponse) { @@ -13,4 +13,4 @@ const options: RequestHandlerOptions = { return session?.user; }, }; -export default RequestHandler(service, options); +export default requestHandler(service, options); diff --git a/samples/todo/pages/index.tsx b/samples/todo/pages/index.tsx index be07c1ab0..b290e3fae 100644 --- a/samples/todo/pages/index.tsx +++ b/samples/todo/pages/index.tsx @@ -1,8 +1,8 @@ import type { NextPage } from 'next'; import LoginButton from '../components/LoginButton'; import { useSession } from 'next-auth/react'; -import { useTodoCollection } from '@zenstackhq/generated/hooks'; -import { TodoCollection } from '@zenstackhq/generated/types'; +import { useTodoCollection } from '@zenstackhq/runtime/hooks'; +import { TodoCollection } from '@zenstackhq/runtime/types'; const Home: NextPage = () => { const { data: session } = useSession(); From 0233926a26ed95606114b8c86bdd7aea0a48ac68 Mon Sep 17 00:00:00 2001 From: Yiming Cao Date: Thu, 13 Oct 2022 12:16:17 +0800 Subject: [PATCH 15/15] update --- packages/schema/package.json | 2 +- packages/schema/src/generator/index.ts | 3 ++- pnpm-lock.yaml | 4 +--- samples/todo/package-lock.json | 12 ++++++------ 4 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/schema/package.json b/packages/schema/package.json index 73bbcd8f1..22f81d582 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -2,7 +2,7 @@ "name": "zenstack", "displayName": "ZenStack CLI and Language Tools", "description": "ZenStack CLI and Language Tools", - "version": "0.1.19", + "version": "0.1.22", "engines": { "vscode": "^1.56.0" }, diff --git a/packages/schema/src/generator/index.ts b/packages/schema/src/generator/index.ts index 90261bf1a..0d5b1056a 100644 --- a/packages/schema/src/generator/index.ts +++ b/packages/schema/src/generator/index.ts @@ -15,7 +15,8 @@ export class ZenStackGenerator { } fs.mkdirSync(context.outDir); - console.log(colors.bold('⌛️ Running ZenStack generators')); + const version = require('../../package.json').version; + console.log(colors.bold(`⌛️ Running ZenStack generator v${version}`)); const generators = [ new PrismaGenerator(), diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 29c7c98e3..ad33ab959 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -46,10 +46,9 @@ importers: '@zenstackhq/internal': ^0.1.0 bcryptjs: ^2.4.3 dependencies: + '@types/bcryptjs': 2.4.2 '@zenstackhq/internal': link:../internal bcryptjs: 2.4.3 - devDependencies: - '@types/bcryptjs': 2.4.2 packages/schema: specifiers: @@ -1157,7 +1156,6 @@ packages: /@types/bcryptjs/2.4.2: resolution: {integrity: sha512-LiMQ6EOPob/4yUL66SZzu6Yh77cbzJFYll+ZfaPiPPFswtIlA/Fs1MzdKYA7JApHU49zQTbJGX3PDmCpIdDBRQ==} - dev: true /@types/cross-spawn/6.0.2: resolution: {integrity: sha512-KuwNhp3eza+Rhu8IFI5HUXRP0LIhqH5cAjubUvGXXthh4YYBuP2ntwEX+Cz8GJoZUHlKo247wPWOfA9LYEq4cw==} diff --git a/samples/todo/package-lock.json b/samples/todo/package-lock.json index 8f42db18e..ee1b16bd6 100644 --- a/samples/todo/package-lock.json +++ b/samples/todo/package-lock.json @@ -4437,9 +4437,9 @@ } }, "node_modules/zenstack": { - "version": "0.1.19", - "resolved": "https://registry.npmjs.org/zenstack/-/zenstack-0.1.19.tgz", - "integrity": "sha512-4sJju87k+5UrXBPqH854iRm4RimQM0IwA1wOoUOltHxD8K9g2qrKC3/DH+d9mSMwbZZ4wvrRdg879g3YJcXfrA==", + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/zenstack/-/zenstack-0.1.21.tgz", + "integrity": "sha512-uhCnyuhUY4XzYz7zeiidq/vIdAAF354t2Nc1YGxX+uvON781w26IUxy2VOmG02P7W3lLBL8zNfE6hNLpqRbzHA==", "dev": true, "dependencies": { "@zenstackhq/internal": "0.1.6", @@ -7623,9 +7623,9 @@ "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" }, "zenstack": { - "version": "0.1.19", - "resolved": "https://registry.npmjs.org/zenstack/-/zenstack-0.1.19.tgz", - "integrity": "sha512-4sJju87k+5UrXBPqH854iRm4RimQM0IwA1wOoUOltHxD8K9g2qrKC3/DH+d9mSMwbZZ4wvrRdg879g3YJcXfrA==", + "version": "0.1.21", + "resolved": "https://registry.npmjs.org/zenstack/-/zenstack-0.1.21.tgz", + "integrity": "sha512-uhCnyuhUY4XzYz7zeiidq/vIdAAF354t2Nc1YGxX+uvON781w26IUxy2VOmG02P7W3lLBL8zNfE6hNLpqRbzHA==", "dev": true, "requires": { "@zenstackhq/internal": "0.1.6",