Skip to content
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
8 changes: 4 additions & 4 deletions packages/functions-tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Returns:

An object containing the generated IDL type and the base type name.

[:link: Source](https://github.com/junobuild/juno-js/tree/main/packages/functions-tools/src/converters/zod-to-idl.ts#L93)
[:link: Source](https://github.com/junobuild/juno-js/tree/main/packages/functions-tools/src/converters/zod-to-idl.ts#L95)

#### :gear: zodToRust

Expand All @@ -56,7 +56,7 @@ Returns:

An object containing the generated Rust code and the base type name.

[:link: Source](https://github.com/junobuild/juno-js/tree/main/packages/functions-tools/src/converters/zod-to-rust.ts#L239)
[:link: Source](https://github.com/junobuild/juno-js/tree/main/packages/functions-tools/src/converters/zod-to-rust.ts#L250)

#### :gear: zodToCandid

Expand Down Expand Up @@ -91,7 +91,7 @@ An object containing the generated Candid type declaration and the base type nam
| `baseName` | `string` | |
| `idl` | `IDL.Type` | |

[:link: Source](https://github.com/junobuild/juno-js/tree/main/packages/functions-tools/src/converters/zod-to-idl.ts#L65)
[:link: Source](https://github.com/junobuild/juno-js/tree/main/packages/functions-tools/src/converters/zod-to-idl.ts#L67)

#### :gear: RustResult

Expand All @@ -100,7 +100,7 @@ An object containing the generated Candid type declaration and the base type nam
| `baseName` | `string` | |
| `code` | `string` | |

[:link: Source](https://github.com/junobuild/juno-js/tree/main/packages/functions-tools/src/converters/zod-to-rust.ts#L208)
[:link: Source](https://github.com/junobuild/juno-js/tree/main/packages/functions-tools/src/converters/zod-to-rust.ts#L219)

#### :gear: CandidResult

Expand Down
4 changes: 2 additions & 2 deletions packages/functions-tools/src/converters/zod-to-candid.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {capitalize} from '@junobuild/utils';
import {capitalize, convertCamelToSnake} from '@junobuild/utils';
import type {z} from 'zod';
import {jsonToSputnikSchema, type SputnikSchemaResult} from './_converters';
import type {SputnikSchema} from './_types';
Expand Down Expand Up @@ -27,7 +27,7 @@ const sputnikSchemaToDid = (schema: SputnikSchema): string => {
if (schema.fields.length === 0) {
return 'record {}';
}
return `record { ${schema.fields.map((f) => `${f.name} : ${sputnikSchemaToDid(f.type)}`).join('; ')} }`;
return `record { ${schema.fields.map((f) => `${convertCamelToSnake(f.name)} : ${sputnikSchemaToDid(f.type)}`).join('; ')} }`;
case 'tuple':
return `record { ${schema.members.map(sputnikSchemaToDid).join('; ')} }`;
case 'indexedTuple':
Expand Down
6 changes: 4 additions & 2 deletions packages/functions-tools/src/converters/zod-to-idl.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {IDL} from '@icp-sdk/core/candid';
import {capitalize} from '@junobuild/utils';
import {capitalize, convertCamelToSnake} from '@junobuild/utils';
import type {z} from 'zod';
import {jsonToSputnikSchema, type SputnikSchemaResult} from './_converters';
import type {SputnikSchema} from './_types';
Expand Down Expand Up @@ -29,7 +29,9 @@ const schemaToIdlType = (schema: SputnikSchema): IDL.Type => {
return IDL.Tuple(...schema.members.map(schemaToIdlType));
case 'record':
return IDL.Record(
Object.fromEntries(schema.fields.map((f) => [f.name, schemaToIdlType(f.type)]))
Object.fromEntries(
schema.fields.map((f) => [convertCamelToSnake(f.name), schemaToIdlType(f.type)])
)
);
case 'variant':
return IDL.Variant(Object.fromEntries(schema.tags.map((t) => [t, IDL.Null])));
Expand Down
21 changes: 16 additions & 5 deletions packages/functions-tools/src/converters/zod-to-rust.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {capitalize} from '@junobuild/utils';
import {capitalize, convertCamelToSnake} from '@junobuild/utils';
import type {z} from 'zod';
import {type SputnikSchemaResult, jsonToSputnikSchema} from './_converters';
import type {SputnikSchema} from './_types';
Expand Down Expand Up @@ -32,6 +32,17 @@ const RUST_KEYWORDS = new Set([
const sanitizeFieldName = (name: string): {name: string; sanitized: boolean} =>
RUST_KEYWORDS.has(name) ? {name: `r#${name}`, sanitized: true} : {name, sanitized: false};

const transformFieldName = (name: string): {name: string; renamed: boolean} => {
const {sanitized, ...rest} = sanitizeFieldName(name);

if (sanitized) {
return {renamed: true, ...rest};
}

const snake = convertCamelToSnake(name);
return {name: snake, renamed: snake !== name};
};

type RustTypeResult =
| {kind: 'primitive'; fieldType: string}
| {kind: 'composite'; fieldType: string; structs: string[]; needsJsonData: boolean};
Expand Down Expand Up @@ -138,8 +149,8 @@ const schemaToRustType = ({

const fields = nonDiscriminatorFields
.map((f, fi) => {
const {name: fieldName, sanitized} = sanitizeFieldName(f.name);
const renameAttr = sanitized ? ` #[serde(rename = "${f.name}")]\n` : '';
const {name: fieldName, renamed} = transformFieldName(f.name);
const renameAttr = renamed ? ` #[serde(rename = "${f.name}")]\n` : '';
return `${renameAttr} ${fieldName}: ${fieldResults[fi].fieldType},`;
})
.join('\n');
Expand Down Expand Up @@ -186,8 +197,8 @@ const schemaToRustType = ({
const fields = schema.fields
.map((f, i) => {
const result = fieldResults[i];
const {name: fieldName, sanitized} = sanitizeFieldName(f.name);
const renameAttr = sanitized ? ` #[serde(rename = "${f.name}")]\n` : '';
const {name: fieldName, renamed} = transformFieldName(f.name);
const renameAttr = renamed ? ` #[serde(rename = "${f.name}")]\n` : '';
const attr =
result.kind === 'composite' && result.needsJsonData ? ' #[json_data(nested)]\n' : '';
return `${renameAttr}${attr} pub ${fieldName}: ${result.fieldType},`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -473,3 +473,11 @@ describe('throws', () => {
z.array(z.union([z.object({a: z.string()}), z.object({b: z.int()})]))
);
});

describe('camelCase field names', () => {
candid(
'WithCamelCaseFields',
z.object({maxResponseBytes: z.bigint().optional(), isReplicated: z.boolean().optional()}),
'record { max_response_bytes : opt nat; is_replicated : opt bool }'
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -222,3 +222,11 @@ describe('discriminated union', () => {
})
);
});

describe('camelCase field names', () => {
idl(
'WithCamelCaseFields',
z.object({maxResponseBytes: z.bigint().optional(), isReplicated: z.boolean().optional()}),
IDL.Record({max_response_bytes: IDL.Opt(IDL.Nat64), is_replicated: IDL.Opt(IDL.Bool)})
);
});
Original file line number Diff line number Diff line change
Expand Up @@ -279,3 +279,11 @@ describe('baseName', () => {
expect(result.baseName).toBe('QueryArgs');
});
});

describe('camelCase field names', () => {
rust(
'myFunction',
z.object({maxResponseBytes: z.bigint().optional(), isReplicated: z.boolean().optional()}),
'#[derive(CandidType, Serialize, Deserialize, Clone, JsonData)]\npub struct MyFunctionArgs {\n #[serde(rename = "maxResponseBytes")]\n pub max_response_bytes: Option<u64>,\n #[serde(rename = "isReplicated")]\n pub is_replicated: Option<bool>,\n}'
);
});