Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge dev to main (v1.10.1) #1099

Merged
merged 2 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zenstack-monorepo",
"version": "1.10.0",
"version": "1.10.1",
"description": "",
"scripts": {
"build": "pnpm -r build",
Expand Down
2 changes: 1 addition & 1 deletion packages/ide/jetbrains/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ plugins {
}

group = "dev.zenstack"
version = "1.10.0"
version = "1.10.1"

repositories {
mavenCentral()
Expand Down
2 changes: 1 addition & 1 deletion packages/ide/jetbrains/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jetbrains",
"version": "1.10.0",
"version": "1.10.1",
"displayName": "ZenStack JetBrains IDE Plugin",
"description": "ZenStack JetBrains IDE plugin",
"homepage": "https://zenstack.dev",
Expand Down
2 changes: 1 addition & 1 deletion packages/language/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/language",
"version": "1.10.0",
"version": "1.10.1",
"displayName": "ZenStack modeling language compiler",
"description": "ZenStack modeling language compiler",
"homepage": "https://zenstack.dev",
Expand Down
2 changes: 1 addition & 1 deletion packages/misc/redwood/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/redwood",
"displayName": "ZenStack RedwoodJS Integration",
"version": "1.10.0",
"version": "1.10.1",
"description": "CLI and runtime for integrating ZenStack with RedwoodJS projects.",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/openapi/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/openapi",
"displayName": "ZenStack Plugin and Runtime for OpenAPI",
"version": "1.10.0",
"version": "1.10.1",
"description": "ZenStack plugin and runtime supporting OpenAPI",
"main": "index.js",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/swr/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/swr",
"displayName": "ZenStack plugin for generating SWR hooks",
"version": "1.10.0",
"version": "1.10.1",
"description": "ZenStack plugin for generating SWR hooks",
"main": "index.js",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/tanstack-query/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/tanstack-query",
"displayName": "ZenStack plugin for generating tanstack-query hooks",
"version": "1.10.0",
"version": "1.10.1",
"description": "ZenStack plugin for generating tanstack-query hooks",
"main": "index.js",
"exports": {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/trpc/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/trpc",
"displayName": "ZenStack plugin for tRPC",
"version": "1.10.0",
"version": "1.10.1",
"description": "ZenStack plugin for tRPC",
"main": "index.js",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/runtime",
"displayName": "ZenStack Runtime Library",
"version": "1.10.0",
"version": "1.10.1",
"description": "Runtime of ZenStack for both client-side and server-side environments.",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"publisher": "zenstack",
"displayName": "ZenStack Language Tools",
"description": "Build scalable web apps with minimum code by defining authorization and validation rules inside the data schema that closer to the database",
"version": "1.10.0",
"version": "1.10.1",
"author": {
"name": "ZenStack Team"
},
Expand Down
10 changes: 9 additions & 1 deletion packages/schema/src/plugins/zod/utils/schema-gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
getAttributeArg,
getAttributeArgLiteral,
getLiteral,
isDataModelFieldReference,
isFromStdlib,
} from '@zenstackhq/sdk';
import {
Expand Down Expand Up @@ -205,10 +206,17 @@ export function makeValidationRefinements(model: DataModel) {
const message = messageArg ? `, { message: ${JSON.stringify(messageArg)} }` : '';

try {
const expr = new TypeScriptExpressionTransformer({
let expr = new TypeScriptExpressionTransformer({
context: ExpressionContext.ValidationRule,
fieldReferenceContext: 'value',
}).transform(valueArg);

if (isDataModelFieldReference(valueArg)) {
// if the expression is a simple field reference, treat undefined
// as true since the all fields are optional in validation context
expr = `${expr} ?? true`;
}

return `.refine((value: any) => ${expr}${message})`;
} catch (err) {
if (err instanceof TypeScriptExpressionTransformerError) {
Expand Down
52 changes: 38 additions & 14 deletions packages/schema/src/utils/typescript-expression-transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
ThisExpr,
UnaryExpr,
} from '@zenstackhq/language/ast';
import { ExpressionContext, getLiteral, isFromStdlib, isFutureExpr } from '@zenstackhq/sdk';
import { ExpressionContext, getLiteral, isDataModelFieldReference, isFromStdlib, isFutureExpr } from '@zenstackhq/sdk';
import { match, P } from 'ts-pattern';
import { getIdFields } from './ast-utils';

Expand Down Expand Up @@ -258,7 +258,13 @@ export class TypeScriptExpressionTransformer {
}

private ensureBoolean(expr: string) {
return `(${expr} ?? false)`;
if (this.options.context === ExpressionContext.ValidationRule) {
// all fields are optional in a validation context, so we treat undefined
// as boolean true
return `(${expr} ?? true)`;
} else {
return `(${expr} ?? false)`;
}
}

// #endregion
Expand Down Expand Up @@ -300,8 +306,18 @@ export class TypeScriptExpressionTransformer {
}
}

private unary(expr: UnaryExpr, normalizeUndefined: boolean): string {
return `(${expr.operator} ${this.transform(expr.operand, normalizeUndefined)})`;
private unary(expr: UnaryExpr, normalizeUndefined: boolean) {
const operand = this.transform(expr.operand, normalizeUndefined);
let result = `(${expr.operator} ${operand})`;
if (
expr.operator === '!' &&
this.options.context === ExpressionContext.ValidationRule &&
isDataModelFieldReference(expr.operand)
) {
// in a validation context, we treat unary involving undefined as boolean true
result = `(${operand} !== undefined ? (${result}): true)`;
}
return result;
}

private isModelType(expr: Expression) {
Expand All @@ -316,16 +332,24 @@ export class TypeScriptExpressionTransformer {
left = `(${left}?.id ?? null)`;
right = `(${right}?.id ?? null)`;
}
const _default = `(${left} ${expr.operator} ${right})`;

let _default = `(${left} ${expr.operator} ${right})`;

if (this.options.context === ExpressionContext.ValidationRule) {
// in a validation context, we treat binary involving undefined as boolean true
if (isDataModelFieldReference(expr.left)) {
_default = `(${left} !== undefined ? (${_default}): true)`;
}
if (isDataModelFieldReference(expr.right)) {
_default = `(${right} !== undefined ? (${_default}): true)`;
}
}
Comment on lines +338 to +346
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The adjustments in the binary method to handle binary expressions based on ExpressionContext.ValidationRule and isDataModelFieldReference are well thought out. These changes ensure that binary operations involving undefined fields in a validation context are treated as boolean true. This consistent approach to handling undefined values in validation contexts across different expression types is commendable. However, it's important to ensure comprehensive testing around these changes to validate their correctness in various scenarios.

Ensure comprehensive testing is conducted around the changes in the binary method to validate their correctness across various scenarios, particularly focusing on edge cases involving undefined values in validation contexts.


return match(expr.operator)
.with(
'in',
() =>
`(${this.transform(expr.right, false)}?.includes(${this.transform(
expr.left,
normalizeUndefined
)}) ?? false)`
.with('in', () =>
this.ensureBoolean(
`${this.transform(expr.right, false)}?.includes(${this.transform(expr.left, normalizeUndefined)})`
)
)
.with(P.union('==', '!='), () => {
if (isThisExpr(expr.left) || isThisExpr(expr.right)) {
Expand Down Expand Up @@ -363,8 +387,8 @@ export class TypeScriptExpressionTransformer {
const predicate = innerTransformer.transform(expr.right, normalizeUndefined);

return match(operator)
.with('?', () => `!!((${operand})?.some((_item: any) => ${predicate}))`)
.with('!', () => `!!((${operand})?.every((_item: any) => ${predicate}))`)
.with('?', () => this.ensureBoolean(`(${operand})?.some((_item: any) => ${predicate})`))
.with('!', () => this.ensureBoolean(`(${operand})?.every((_item: any) => ${predicate})`))
.with('^', () => `!((${operand})?.some((_item: any) => ${predicate}))`)
.exhaustive();
}
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/sdk",
"version": "1.10.0",
"version": "1.10.1",
"description": "ZenStack plugin development SDK",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/server",
"version": "1.10.0",
"version": "1.10.1",
"displayName": "ZenStack Server-side Adapters",
"description": "ZenStack server-side adapters",
"homepage": "https://zenstack.dev",
Expand Down
2 changes: 1 addition & 1 deletion packages/testtools/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/testtools",
"version": "1.10.0",
"version": "1.10.1",
"description": "ZenStack Test Tools",
"main": "index.js",
"private": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/testtools/src/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ plugin policy {

plugin zod {
provider = '@core/zod'
// preserveTsFiles = true
preserveTsFiles = true
modelOnly = ${!options.fullZod}
}
`;
Comment on lines 105 to 111
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [40-40]

The use of execSync with command concatenation in the run function could potentially lead to command injection vulnerabilities if user-controlled input is passed to this function. Ensure that all inputs to this function are properly sanitized or validated to prevent malicious command execution.

  • Implement input validation or sanitization for the cmd parameter in the run function to mitigate the risk of command injection.

📝 NOTE
This review was outside the diff hunks, and no overlapping diff hunk was found. Original lines [64-64]

The use of path.join with potentially user-controlled input in functions like getWorkspaceRoot and getWorkspaceNpmCacheFolder could lead to path traversal vulnerabilities. It's crucial to ensure that any user input is properly sanitized or validated before being used in file path operations.

  • Sanitize or validate user input before using it in path.join or path.resolve functions to prevent path traversal vulnerabilities.

Also applies to: 75-75

Expand Down
1 change: 1 addition & 0 deletions tests/integration/tests/cli/plugins.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ describe('CLI Plugins Tests', () => {
strict: true,
lib: ['esnext', 'dom'],
esModuleInterop: true,
skipLibCheck: true,
},
})
);
Expand Down
Loading
Loading