diff --git a/e2e-tests/bug-rust-repro/src/generated/parser.js b/e2e-tests/bug-rust-repro/src/generated/parser.js index 8cf90e0a..2d95a028 100644 --- a/e2e-tests/bug-rust-repro/src/generated/parser.js +++ b/e2e-tests/bug-rust-repro/src/generated/parser.js @@ -4,7 +4,7 @@ import {printErrors} from '@beff/client'; import {z} from 'zod'; -import validatorsMod from "./validators.js"; const { decodeObject, decodeArray, decodeString, decodeNumber, decodeCodec, decodeStringWithFormat, decodeAnyOf, decodeAllOf, decodeBoolean, decodeAny, decodeTuple, decodeNull, decodeConst, registerCustomFormatter, validators, c } = validatorsMod; +import validatorsMod from "./validators.js"; const { decodeObject, decodeArray, decodeString, decodeNumber, decodeCodec, decodeFunction, decodeStringWithFormat, decodeAnyOf, decodeAllOf, decodeBoolean, decodeAny, decodeTuple, decodeNull, decodeConst, registerCustomFormatter, validators, c } = validatorsMod; const RequiredCustomFormats = ["ValidCurrency"]; const buildParsersInput = { "A": function(ctx, input, required = true) { diff --git a/e2e-tests/bug-rust-repro/src/generated/validators.js b/e2e-tests/bug-rust-repro/src/generated/validators.js index 48bd31f1..4934a0f3 100644 --- a/e2e-tests/bug-rust-repro/src/generated/validators.js +++ b/e2e-tests/bug-rust-repro/src/generated/validators.js @@ -130,6 +130,16 @@ function decodeNumber(ctx, input, required) { return buildError(input, ctx, "expected number"); } +function decodeFunction(ctx, input, required) { + if (!required && input == null) { + return input; + } + if (typeof input === "function") { + return input; + } + return buildError(input, ctx, "expected function"); +} + function decodeCodec(ctx, input, required, codec) { if (!required && input == null) { return input; @@ -336,4 +346,4 @@ const validators = { A: DecodeA }; -export default { decodeObject, decodeArray, decodeString, decodeNumber, decodeCodec, decodeStringWithFormat, decodeAnyOf, decodeAllOf, decodeBoolean, decodeAny, decodeTuple, decodeNull, decodeConst, registerCustomFormatter, validators }; \ No newline at end of file +export default { decodeObject, decodeArray, decodeString, decodeNumber, decodeCodec, decodeFunction, decodeStringWithFormat, decodeAnyOf, decodeAllOf, decodeBoolean, decodeAny, decodeTuple, decodeNull, decodeConst, registerCustomFormatter, validators }; \ No newline at end of file diff --git a/e2e-tests/standalone-parser/CHANGELOG.md b/e2e-tests/standalone-parser/CHANGELOG.md index 46985389..6a0769ea 100644 --- a/e2e-tests/standalone-parser/CHANGELOG.md +++ b/e2e-tests/standalone-parser/CHANGELOG.md @@ -1,5 +1,13 @@ # node-server +## 1.0.54 + +### Patch Changes + +- Updated dependencies + - @beff/cli@0.0.57 + - @beff/client@0.0.57 + ## 1.0.53 ### Patch Changes diff --git a/e2e-tests/standalone-parser/package.json b/e2e-tests/standalone-parser/package.json index 2d5e49c3..bdba93fa 100644 --- a/e2e-tests/standalone-parser/package.json +++ b/e2e-tests/standalone-parser/package.json @@ -1,6 +1,6 @@ { "name": "standalone-parser", - "version": "1.0.53", + "version": "1.0.54", "description": "", "main": "index.js", "scripts": { @@ -11,7 +11,7 @@ "author": "", "license": "ISC", "dependencies": { - "@beff/cli": "workspace:^0.0.56", + "@beff/cli": "workspace:^0.0.57", "@beff/client": "workspace:^", "vitest": "^0.34.4", "zod": "^3.23.5" diff --git a/e2e-tests/standalone-parser/src/generated/parser.js b/e2e-tests/standalone-parser/src/generated/parser.js index c25e37bf..d0b00ac3 100644 --- a/e2e-tests/standalone-parser/src/generated/parser.js +++ b/e2e-tests/standalone-parser/src/generated/parser.js @@ -4,7 +4,7 @@ import {printErrors} from '@beff/client'; import {z} from 'zod'; -import validatorsMod from "./validators.js"; const { decodeObject, decodeArray, decodeString, decodeNumber, decodeCodec, decodeStringWithFormat, decodeAnyOf, decodeAllOf, decodeBoolean, decodeAny, decodeTuple, decodeNull, decodeConst, registerCustomFormatter, validators, c } = validatorsMod; +import validatorsMod from "./validators.js"; const { decodeObject, decodeArray, decodeString, decodeNumber, decodeCodec, decodeFunction, decodeStringWithFormat, decodeAnyOf, decodeAllOf, decodeBoolean, decodeAny, decodeTuple, decodeNull, decodeConst, registerCustomFormatter, validators, c } = validatorsMod; const RequiredCustomFormats = ["ValidCurrency"]; const buildParsersInput = { "AObject": function(ctx, input, required = true) { diff --git a/e2e-tests/standalone-parser/src/generated/validators.js b/e2e-tests/standalone-parser/src/generated/validators.js index bf6a7f33..98cc6164 100644 --- a/e2e-tests/standalone-parser/src/generated/validators.js +++ b/e2e-tests/standalone-parser/src/generated/validators.js @@ -130,6 +130,16 @@ function decodeNumber(ctx, input, required) { return buildError(input, ctx, "expected number"); } +function decodeFunction(ctx, input, required) { + if (!required && input == null) { + return input; + } + if (typeof input === "function") { + return input; + } + return buildError(input, ctx, "expected function"); +} + function decodeCodec(ctx, input, required, codec) { if (!required && input == null) { return input; @@ -677,4 +687,4 @@ const validators = { BObject: DecodeBObject }; -export default { decodeObject, decodeArray, decodeString, decodeNumber, decodeCodec, decodeStringWithFormat, decodeAnyOf, decodeAllOf, decodeBoolean, decodeAny, decodeTuple, decodeNull, decodeConst, registerCustomFormatter, validators }; \ No newline at end of file +export default { decodeObject, decodeArray, decodeString, decodeNumber, decodeCodec, decodeFunction, decodeStringWithFormat, decodeAnyOf, decodeAllOf, decodeBoolean, decodeAny, decodeTuple, decodeNull, decodeConst, registerCustomFormatter, validators }; \ No newline at end of file diff --git a/packages/beff-cli/CHANGELOG.md b/packages/beff-cli/CHANGELOG.md index 2a0e8b6b..7becf385 100644 --- a/packages/beff-cli/CHANGELOG.md +++ b/packages/beff-cli/CHANGELOG.md @@ -1,5 +1,11 @@ # @beff/cli +## 0.0.57 + +### Patch Changes + +- func types + ## 0.0.56 ### Patch Changes diff --git a/packages/beff-cli/package.json b/packages/beff-cli/package.json index 97446425..7824b52e 100644 --- a/packages/beff-cli/package.json +++ b/packages/beff-cli/package.json @@ -1,6 +1,6 @@ { "name": "@beff/cli", - "version": "0.0.56", + "version": "0.0.57", "description": "", "bin": { "beff": "./bin/index.js" diff --git a/packages/beff-client/CHANGELOG.md b/packages/beff-client/CHANGELOG.md index 588e1908..b21b9437 100644 --- a/packages/beff-client/CHANGELOG.md +++ b/packages/beff-client/CHANGELOG.md @@ -1,5 +1,13 @@ # @beff/client +## 0.0.57 + +### Patch Changes + +- func types +- Updated dependencies + - @beff/cli@0.0.57 + ## 0.0.56 ### Patch Changes diff --git a/packages/beff-client/package.json b/packages/beff-client/package.json index 15102fc8..276cabc1 100644 --- a/packages/beff-client/package.json +++ b/packages/beff-client/package.json @@ -1,6 +1,6 @@ { "name": "@beff/client", - "version": "0.0.56", + "version": "0.0.57", "description": "", "main": "dist/cjs/index.js", "scripts": { @@ -20,7 +20,7 @@ "author": "", "license": "ISC", "dependencies": { - "@beff/cli": "workspace:^0.0.56", + "@beff/cli": "workspace:^0.0.57", "zod": "^3.23.5" }, "devDependencies": { diff --git a/packages/beff-core/src/ast/json_schema.rs b/packages/beff-core/src/ast/json_schema.rs index 9a424300..efdcaf32 100644 --- a/packages/beff-core/src/ast/json_schema.rs +++ b/packages/beff-core/src/ast/json_schema.rs @@ -18,6 +18,7 @@ use swc_ecma_ast::TplElement; use swc_ecma_ast::TsArrayType; use swc_ecma_ast::TsEntityName; use swc_ecma_ast::TsFnParam; +use swc_ecma_ast::TsFnType; use swc_ecma_ast::TsIndexSignature; use swc_ecma_ast::TsIntersectionType; use swc_ecma_ast::TsKeywordType; @@ -247,6 +248,7 @@ pub enum JsonSchema { // semantic types StNever, StNot(Box), + Function, } #[derive(PartialEq, Eq, Hash, Debug, Ord, PartialOrd, Clone)] @@ -410,26 +412,27 @@ impl<'a> JsonFlatConverter<'a> { } #[allow(clippy::cast_precision_loss)] - pub fn to_json_flat(&mut self, schema: JsonSchema) -> Json { + pub fn to_json_flat(&mut self, schema: JsonSchema) -> anyhow::Result { match schema { - JsonSchema::String => { - Json::object(vec![("type".into(), Json::String("string".into()))]) - } - JsonSchema::StringWithFormat(format) => Json::object(vec![ + JsonSchema::String => Ok(Json::object(vec![( + "type".into(), + Json::String("string".into()), + )])), + JsonSchema::StringWithFormat(format) => Ok(Json::object(vec![ ("type".into(), Json::String("string".into())), ("format".into(), Json::String(format)), - ]), - JsonSchema::Codec(format) => Json::object(vec![ + ])), + JsonSchema::Codec(format) => Ok(Json::object(vec![ ("type".into(), Json::String("string".into())), ("format".into(), Json::String(format.to_string())), - ]), - JsonSchema::TplLitType(items) => Json::object(vec![ + ])), + JsonSchema::TplLitType(items) => Ok(Json::object(vec![ ("type".into(), Json::String("string".into())), ( "format".into(), Json::String(TplLitTypeItem::describe_vec(&items)), ), - ]), + ])), JsonSchema::Object { vs: values, rest } => { let mut vs = vec![ @@ -452,37 +455,39 @@ impl<'a> JsonFlatConverter<'a> { Json::Object( values .into_iter() - .map(|(k, v)| (k, self.to_json_flat(v.inner_move()))) - .collect(), + .map(|(k, v)| self.to_json_flat(v.inner_move()).map(|v| (k, v))) + .collect::>>()?, ), ), ]; if let Some(rest) = rest { - vs.push(("additionalProperties".into(), self.to_json_flat(*rest))); + vs.push(("additionalProperties".into(), self.to_json_flat(*rest)?)); } else { vs.push(("additionalProperties".into(), Json::Bool(false))); } - Json::object(vs) + Ok(Json::object(vs)) } JsonSchema::Array(typ) => { - Json::object(vec![ + Ok(Json::object(vec![ // ("type".into(), Json::String("array".into())), - ("items".into(), self.to_json_flat(*typ)), - ]) - } - JsonSchema::Boolean => { - Json::object(vec![("type".into(), Json::String("boolean".into()))]) + ("items".into(), self.to_json_flat(*typ)?), + ])) } - JsonSchema::Number => { - Json::object(vec![("type".into(), Json::String("number".into()))]) - } - JsonSchema::Any => Json::object(vec![]), + JsonSchema::Boolean => Ok(Json::object(vec![( + "type".into(), + Json::String("boolean".into()), + )])), + JsonSchema::Number => Ok(Json::object(vec![( + "type".into(), + Json::String("number".into()), + )])), + JsonSchema::Any => Ok(Json::object(vec![])), JsonSchema::Ref(reference) => { if self.seen_refs.contains(&reference) { // recursive type, let's return "ANY" - return Json::object(vec![]); + return Ok(Json::object(vec![])); } let validator = self .validators @@ -496,7 +501,10 @@ impl<'a> JsonFlatConverter<'a> { json } - JsonSchema::Null => Json::object(vec![("type".into(), Json::String("null".into()))]), + JsonSchema::Null => Ok(Json::object(vec![( + "type".into(), + Json::String("null".into()), + )])), JsonSchema::AnyOf(types) => { let all_literals = types.iter().all(|it| matches!(it, JsonSchema::Const(_))); if all_literals { @@ -510,22 +518,30 @@ impl<'a> JsonFlatConverter<'a> { let all_strings = vs.iter().all(|it| matches!(it, Json::String(_))); if all_strings { - Json::object(vec![ + Ok(Json::object(vec![ ("enum".into(), Json::Array(vs)), ("type".into(), Json::String("string".into())), - ]) + ])) } else { - Json::object(vec![("enum".into(), Json::Array(vs))]) + Ok(Json::object(vec![("enum".into(), Json::Array(vs))])) } } else { - let vs = types.into_iter().map(|it| self.to_json_flat(it)).collect(); - Json::object(vec![("anyOf".into(), Json::Array(vs))]) + let vs = types + .into_iter() + .map(|it| self.to_json_flat(it)) + .collect::>()?; + Ok(Json::object(vec![("anyOf".into(), Json::Array(vs))])) } } - JsonSchema::AllOf(types) => Json::object(vec![( - "allOf".into(), - Json::Array(types.into_iter().map(|it| self.to_json_flat(it)).collect()), - )]), + JsonSchema::AllOf(types) => { + let mut arr_types = vec![]; + + for t in types { + arr_types.push(self.to_json_flat(t)?); + } + + Ok(Json::object(vec![("allOf".into(), Json::Array(arr_types))])) + } JsonSchema::Tuple { prefix_items, @@ -543,25 +559,26 @@ impl<'a> JsonFlatConverter<'a> { prefix_items .into_iter() .map(|it| self.to_json_flat(it)) - .collect(), + .collect::>()?, ), )); } if let Some(ty) = items { - v.push(("items".into(), self.to_json_flat(*ty))); + v.push(("items".into(), self.to_json_flat(*ty)?)); } else { v.push(("minItems".into(), Json::parse_int(len_f as i64))); v.push(("maxItems".into(), Json::parse_int(len_f as i64))); } - Json::object(v) + Ok(Json::object(v)) } - JsonSchema::Const(val) => Json::object(vec![("const".into(), val.to_json())]), + JsonSchema::Const(val) => Ok(Json::object(vec![("const".into(), val.to_json())])), JsonSchema::AnyArrayLike => { self.to_json_flat(JsonSchema::Array(JsonSchema::Any.into())) } JsonSchema::StNever | JsonSchema::StNot(_) => { - unreachable!("semantic types should not be converted to json") + Err(anyhow!("semantic types should not be converted to json")) } + JsonSchema::Function => Err(anyhow!("function type is not supported in json schema"))?, } } } @@ -1005,6 +1022,22 @@ impl JsonSchema { }), }) } + JsonSchema::Function => TsType::TsFnOrConstructorType( + swc_ecma_ast::TsFnOrConstructorType::TsFnType(TsFnType { + span: DUMMY_SP, + params: vec![], + type_params: None, + type_ann: TsTypeAnn { + span: DUMMY_SP, + type_ann: TsType::TsKeywordType(TsKeywordType { + span: DUMMY_SP, + kind: TsKeywordTypeKind::TsVoidKeyword, + }) + .into(), + } + .into(), + }), + ), } } } diff --git a/packages/beff-core/src/lib.rs b/packages/beff-core/src/lib.rs index 9ed43c9c..ec012e74 100644 --- a/packages/beff-core/src/lib.rs +++ b/packages/beff-core/src/lib.rs @@ -421,10 +421,10 @@ pub struct Validator { pub schema: JsonSchema, } impl Validator { - pub fn to_json_kv(&self, validators: &[Validator]) -> Vec<(String, Json)> { - vec![( + pub fn to_json_kv(&self, validators: &[Validator]) -> anyhow::Result> { + Ok(vec![( self.name.clone(), - JsonFlatConverter::new(validators).to_json_flat(self.schema.clone()), - )] + JsonFlatConverter::new(validators).to_json_flat(self.schema.clone())?, + )]) } } diff --git a/packages/beff-core/src/parser_extractor.rs b/packages/beff-core/src/parser_extractor.rs index b0799e13..70899f1e 100644 --- a/packages/beff-core/src/parser_extractor.rs +++ b/packages/beff-core/src/parser_extractor.rs @@ -23,11 +23,11 @@ pub struct BuiltDecoder { pub schema: JsonSchema, } impl BuiltDecoder { - pub fn to_json_kv(&self, validators: &[Validator]) -> Vec<(String, Json)> { - vec![( + pub fn to_json_kv(&self, validators: &[Validator]) -> anyhow::Result> { + Ok(vec![( self.exported_name.clone(), - JsonFlatConverter::new(validators).to_json_flat(self.schema.clone()), - )] + JsonFlatConverter::new(validators).to_json_flat(self.schema.clone())?, + )]) } } diff --git a/packages/beff-core/src/print/decoder.rs b/packages/beff-core/src/print/decoder.rs index cca01b47..6e65b54c 100644 --- a/packages/beff-core/src/print/decoder.rs +++ b/packages/beff-core/src/print/decoder.rs @@ -552,6 +552,7 @@ impl<'a> DecoderFnGenerator<'a> { ], ) } + JsonSchema::Function => Self::decode_call("decodeFunction", required), } } diff --git a/packages/beff-core/src/print/printer.rs b/packages/beff-core/src/print/printer.rs index e51cada2..883a98e1 100644 --- a/packages/beff-core/src/print/printer.rs +++ b/packages/beff-core/src/print/printer.rs @@ -168,7 +168,10 @@ impl ToWritableModules for ExtractResult { let json_schema_obj = Json::object( decoders .iter() - .flat_map(|it| BuiltDecoder::to_json_kv(it, &validators)) + .map(|it| BuiltDecoder::to_json_kv(it, &validators)) + .collect::>>>()? + .into_iter() + .flatten() .collect(), ); // schema diff --git a/packages/beff-core/src/subtyping/mod.rs b/packages/beff-core/src/subtyping/mod.rs index 762a2ad2..20fae1d0 100644 --- a/packages/beff-core/src/subtyping/mod.rs +++ b/packages/beff-core/src/subtyping/mod.rs @@ -214,6 +214,7 @@ impl<'a> ToSemTypeConverter<'a> { let chd = self.convert_to_sem_type(it, builder)?; Ok(chd.complement()) } + JsonSchema::Function => Ok(SemTypeContext::function().into()), } } } diff --git a/packages/beff-core/src/subtyping/semtype.rs b/packages/beff-core/src/subtyping/semtype.rs index 79850b6a..bdb4f21b 100644 --- a/packages/beff-core/src/subtyping/semtype.rs +++ b/packages/beff-core/src/subtyping/semtype.rs @@ -466,6 +466,9 @@ impl SemTypeContext { SemType::new_unknown() } + pub(crate) fn function() -> SemType { + SemType::new_basic(SubTypeTag::Function.code()) + } fn get_complex_sub_type_data(s: &Vec>, tag: SubTypeTag) -> SubType { for t in s { match (t.as_ref(), &tag) { diff --git a/packages/beff-core/src/subtyping/subtype.rs b/packages/beff-core/src/subtyping/subtype.rs index 1b7e3e3f..9612830f 100644 --- a/packages/beff-core/src/subtyping/subtype.rs +++ b/packages/beff-core/src/subtyping/subtype.rs @@ -1,6 +1,9 @@ use std::rc::Rc; -use crate::ast::{json::N, json_schema::{CodecName, TplLitTypeItem}}; +use crate::ast::{ + json::N, + json_schema::{CodecName, TplLitTypeItem}, +}; use super::{ bdd::{list_is_empty, mapping_is_empty, Bdd, BddOps}, @@ -22,9 +25,10 @@ pub enum SubTypeTag { Mapping = 1 << 0x5, Void = 1 << 0x6, List = 1 << 0x7, + Function = 1 << 0x8, } -pub const VAL: u32 = 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7; +pub const VAL: u32 = 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7 | 1 << 8; impl SubTypeTag { pub fn code(&self) -> BasicTypeCode { @@ -41,6 +45,7 @@ impl SubTypeTag { SubTypeTag::Null, SubTypeTag::Mapping, SubTypeTag::List, + SubTypeTag::Function, ] } } diff --git a/packages/beff-core/src/subtyping/to_schema.rs b/packages/beff-core/src/subtyping/to_schema.rs index 226632d7..2773fa75 100644 --- a/packages/beff-core/src/subtyping/to_schema.rs +++ b/packages/beff-core/src/subtyping/to_schema.rs @@ -440,6 +440,9 @@ impl<'a, 'b> SchemerContext<'a, 'b> { SubTypeTag::List => { acc.insert(JsonSchema::AnyArrayLike); } + SubTypeTag::Function => { + acc.insert(JsonSchema::Function); + } }; } } diff --git a/packages/beff-core/src/type_to_schema.rs b/packages/beff-core/src/type_to_schema.rs index 73c67b8d..ec6af8f5 100644 --- a/packages/beff-core/src/type_to_schema.rs +++ b/packages/beff-core/src/type_to_schema.rs @@ -1375,6 +1375,7 @@ impl<'a, 'b, R: FileManager> TypeToSchema<'a, 'b, R> { })?; self.convert_sem_type(access_st, &mut ctx, &m.prop.span()) } + Expr::Arrow(_a) => Ok(JsonSchema::Function), _ => { dbg!(&e); self.error(&e.span(), DiagnosticInfoMessage::CannotConvertExprToSchema) diff --git a/packages/beff-core/tests/print_parser.rs b/packages/beff-core/tests/print_parser.rs index 308894f2..fd1d6cb0 100644 --- a/packages/beff-core/tests/print_parser.rs +++ b/packages/beff-core/tests/print_parser.rs @@ -540,6 +540,15 @@ mod tests { "#)); } #[test] + fn ok_repro9() { + insta::assert_snapshot!(ok(r#" + export const ABC = {a: x=>x+1, } as const satisfies Record; + export type AllTs = (keyof typeof ABC); + + parse.buildParsers<{ AllTs: AllTs }>(); + "#)); + } + #[test] fn ok_void() { insta::assert_snapshot!(ok(r#" export type IX = void diff --git a/packages/beff-core/tests/snapshots/print_parser__tests__ok_repro9.snap b/packages/beff-core/tests/snapshots/print_parser__tests__ok_repro9.snap new file mode 100644 index 00000000..cfb1d17a --- /dev/null +++ b/packages/beff-core/tests/snapshots/print_parser__tests__ok_repro9.snap @@ -0,0 +1,6 @@ +--- +source: packages/beff-core/tests/print_parser.rs +expression: "ok(r#\"\n export const ABC = {a: x=>x+1, } as const satisfies Record;\n export type AllTs = (keyof typeof ABC);\n\n parse.buildParsers<{ AllTs: AllTs }>();\n \"#)" +--- +type AllTs = "a"; +type AllTs = AllTs; diff --git a/packages/beff-wasm/bundled-code/decoders.js b/packages/beff-wasm/bundled-code/decoders.js index 7d24e0e3..2883c2ae 100644 --- a/packages/beff-wasm/bundled-code/decoders.js +++ b/packages/beff-wasm/bundled-code/decoders.js @@ -127,6 +127,16 @@ function decodeNumber(ctx, input, required) { return buildError(input, ctx, "expected number"); } +function decodeFunction(ctx, input, required) { + if (!required && input == null) { + return input; + } + if (typeof input === "function") { + return input; + } + return buildError(input, ctx, "expected function"); +} + function decodeCodec(ctx, input, required, codec) { if (!required && input == null) { return input; diff --git a/packages/beff-wasm/fixtures/codegen-snaps/export-decoder/bff-generated/parser.js b/packages/beff-wasm/fixtures/codegen-snaps/export-decoder/bff-generated/parser.js index b6a4ed0d..1eaf7629 100644 --- a/packages/beff-wasm/fixtures/codegen-snaps/export-decoder/bff-generated/parser.js +++ b/packages/beff-wasm/fixtures/codegen-snaps/export-decoder/bff-generated/parser.js @@ -4,7 +4,7 @@ import {printErrors} from '@beff/client'; import {z} from 'zod'; -import validatorsMod from "./validators.js"; const { decodeObject, decodeArray, decodeString, decodeNumber, decodeCodec, decodeStringWithFormat, decodeAnyOf, decodeAllOf, decodeBoolean, decodeAny, decodeTuple, decodeNull, decodeConst, registerCustomFormatter, validators, c } = validatorsMod; +import validatorsMod from "./validators.js"; const { decodeObject, decodeArray, decodeString, decodeNumber, decodeCodec, decodeFunction, decodeStringWithFormat, decodeAnyOf, decodeAllOf, decodeBoolean, decodeAny, decodeTuple, decodeNull, decodeConst, registerCustomFormatter, validators, c } = validatorsMod; const RequiredCustomFormats = ["password","StartsWithA"]; const buildParsersInput = { "NotPublicRenamed": function(ctx, input, required = true) { diff --git a/packages/beff-wasm/fixtures/codegen-snaps/export-decoder/bff-generated/validators.js b/packages/beff-wasm/fixtures/codegen-snaps/export-decoder/bff-generated/validators.js index adb09da1..1362680d 100644 --- a/packages/beff-wasm/fixtures/codegen-snaps/export-decoder/bff-generated/validators.js +++ b/packages/beff-wasm/fixtures/codegen-snaps/export-decoder/bff-generated/validators.js @@ -130,6 +130,16 @@ function decodeNumber(ctx, input, required) { return buildError(input, ctx, "expected number"); } +function decodeFunction(ctx, input, required) { + if (!required && input == null) { + return input; + } + if (typeof input === "function") { + return input; + } + return buildError(input, ctx, "expected function"); +} + function decodeCodec(ctx, input, required, codec) { if (!required && input == null) { return input; @@ -392,4 +402,4 @@ const validators = { UnionNested: DecodeUnionNested }; -export default { decodeObject, decodeArray, decodeString, decodeNumber, decodeCodec, decodeStringWithFormat, decodeAnyOf, decodeAllOf, decodeBoolean, decodeAny, decodeTuple, decodeNull, decodeConst, registerCustomFormatter, validators }; \ No newline at end of file +export default { decodeObject, decodeArray, decodeString, decodeNumber, decodeCodec, decodeFunction, decodeStringWithFormat, decodeAnyOf, decodeAllOf, decodeBoolean, decodeAny, decodeTuple, decodeNull, decodeConst, registerCustomFormatter, validators }; \ No newline at end of file diff --git a/packages/beff-wasm/package.json b/packages/beff-wasm/package.json index 59cd0bcd..995967d1 100644 --- a/packages/beff-wasm/package.json +++ b/packages/beff-wasm/package.json @@ -41,7 +41,7 @@ }, "devDependencies": { "@babel/code-frame": "^7.22.13", - "@beff/cli": "workspace:^0.0.56", + "@beff/cli": "workspace:^0.0.57", "@types/babel__code-frame": "^7.0.4", "@types/node": "^20.6.2", "@types/vscode": "^1.73.0", diff --git a/packages/beff-wasm/ts-node/bundle-to-disk.ts b/packages/beff-wasm/ts-node/bundle-to-disk.ts index c1da51ca..7d8737a7 100644 --- a/packages/beff-wasm/ts-node/bundle-to-disk.ts +++ b/packages/beff-wasm/ts-node/bundle-to-disk.ts @@ -10,6 +10,7 @@ const decodersExported = [ "decodeString", "decodeNumber", "decodeCodec", + "decodeFunction", "decodeStringWithFormat", "decodeAnyOf", "decodeAllOf", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d984dfe0..4c5ce949 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,7 +34,7 @@ importers: e2e-tests/standalone-parser: dependencies: '@beff/cli': - specifier: workspace:^0.0.56 + specifier: workspace:^0.0.57 version: link:../../packages/beff-cli '@beff/client': specifier: workspace:^ @@ -55,7 +55,7 @@ importers: packages/beff-client: dependencies: '@beff/cli': - specifier: workspace:^0.0.56 + specifier: workspace:^0.0.57 version: link:../beff-cli zod: specifier: ^3.23.5 @@ -89,7 +89,7 @@ importers: specifier: ^7.22.13 version: 7.22.13 '@beff/cli': - specifier: workspace:^0.0.56 + specifier: workspace:^0.0.57 version: link:../beff-cli '@types/babel__code-frame': specifier: ^7.0.4