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

Can't figure out how to escape angled brackets <> w/ Handlebars #300

Open
andenacitelli opened this issue Jul 29, 2024 · 2 comments
Open

Comments

@andenacitelli
Copy link
Contributor

andenacitelli commented Jul 29, 2024

Describe the bug

I'm seeing angled brackets <> that are not being used in a HTML context still be stripped, and have been unable to figure out how to properly escape them.

Minimal reproduction

I'm running this command (the OpenAPI spec is a public link):

openapi-zod-client https://raw.githubusercontent.com/aacitelli/credit-card-bonuses-api/main/src/api.yaml -t schemas-only.hbs --output src/.generated/open-api-zod.ts --export-schemas

With this Handlebars template:

import { z } from "zod";

{{#each schemas}}
export const {{@key}} = {{{this}}};
export type {{@key}} = z.infer<typeof {{@key}}>;
{{/each}}

export const schemas = {
{{#each schemas}}
	{{@key}},
{{/each}}
};

But I'm seeing the <typeof ...> part seemingly get treated as HTML-related and wiped by the Handlebars process. This is what it looks like:

import { z } from "zod";

export const IssuersEnum = z.enum([
  "AMERICAN_EXPRESS",
  "BANK_OF_AMERICA",
  "BARCLAYS",
  "BREX",
  "CHASE",
  "CAPITAL_ONE",
  "CITI",
  "FIRST",
  "FNBO",
  "PENFED",
  "PNC",
  "SYNCHRONY",
  "US_BANK",
  "WELLS_FARGO",
]);
export type IssuersEnum = z.infer;
export const NetworksEnum = z.enum([
  "VISA",
  "MASTERCARD",
  "AMERICAN_EXPRESS",
  "DISCOVER",
]);
export type NetworksEnum = z.infer;
export const CurrenciesEnum = z.enum([
  "BEST_WESTERN",
  "BREEZE",
  "HILTON",
  "HYATT",
  "IHG",
  "MARRIOTT",
  "RADISSON",
  "WYNDHAM",
  "CHOICE",
  "AEROPLAN",
  "ALASKA",
  "AMERICAN",
  "ANA",
  "AVIANCA",
  "AVIOS",
  "CATHAY_PACIFIC",
  "DELTA",
  "EMIRATES",
  "FRONTIER",
  "FLYING_BLUE",
  "HAWAIIAN",
  "JETBLUE",
  "KOREAN",
  "LATAM",
  "LUFTHANSA",
  "SOUTHWEST",
  "SPIRIT",
  "UNITED",
  "VIRGIN",
  "AMERICAN_EXPRESS",
  "BANK_OF_AMERICA",
  "BARCLAYS",
  "BILT",
  "BREX",
  "CHASE",
  "CITI",
  "CAPITAL_ONE",
  "DISCOVER",
  "US_BANK",
  "WELLS_FARGO",
  "CARNIVAL",
  "AMTRAK",
  "PENFED",
  "USD",
]);
export type CurrenciesEnum = z.infer;
export const Credit = z
  .object({
    description: z.string().min(1),
    value: z.number(),
    weight: z.number().gte(0).lte(1),
    currency: CurrenciesEnum.optional(),
  })
  .passthrough();
export type Credit = z.infer;
export const OfferAmount = z
  .object({ amount: z.number(), currency: CurrenciesEnum.optional() })
  .passthrough();
export type OfferAmount = z.infer;
export const Offer = z
  .object({
    spend: z.number().gte(0),
    amount: z.array(OfferAmount),
    days: z.number().gte(30),
    expiration: z.string().optional(),
    isPublic: z.boolean().optional(),
    credits: z.array(Credit),
    details: z.string().optional(),
    url: z.string().optional(),
    referralUrl: z.string().optional(),
  })
  .passthrough();
export type Offer = z.infer;
export const CreditCard = z
  .object({
    name: z.string().min(1),
    issuer: IssuersEnum,
    network: NetworksEnum,
    currency: CurrenciesEnum,
    countsTowards524: z.boolean().optional(),
    details: z.string().optional(),
    isBusiness: z.boolean(),
    annualFee: z.number(),
    isAnnualFeeWaived: z.boolean(),
    universalCashbackPercent: z.number().gte(1).lte(100),
    url: z.string(),
    imageUrl: z.string(),
    credits: z.array(Credit),
    offers: z.array(Offer),
    historicalOffers: z.array(Offer),
  })
  .passthrough();
export type CreditCard = z.infer;

export const schemas = {
  IssuersEnum,
  NetworksEnum,
  CurrenciesEnum,
  Credit,
  OfferAmount,
  Offer,
  CreditCard,
};

Expected behavior

I expect the z.infer to have the <typeof xyz_schema_name> present.

Additional context

This started happening a few months back and I haven't been able to nail down why, as it used to work.

@andenacitelli andenacitelli changed the title Can't figure out how to escape angled brackets <> Can't figure out how to escape angled brackets <> w/ Handlebars Jul 29, 2024
@codemariner
Copy link

i'm just now also running into this same problem. There's something wonky about how it processes the handlebars template. it's like it sees it as an html tag no matter what I do. I can put some \ and it will output it, but it doesn't treat it like an escape character (also prints \). Sometimes I really hate handlebars for how confining it is.

@codemariner
Copy link

codemariner commented Aug 24, 2024

so, it looks like it has to do with the prettier config. It seems to pick up whatever you have locally. When I removed mine (which works just fine for me) it started working. Here's my prettier config.

// ./.prettierrc.cjs
module.exports = {
  singleQuote: true,
  semi: false,
  plugins: ['@trivago/prettier-plugin-sort-imports'],
  importOrder: ['<THIRD_PARTY_MODULES>', '^@banno/(.*)$', '^[./]'], // for @trivago/prettier-plugin-sort-imports
  importOrderSeparation: true, // for @trivago/prettier-plugin-sort-imports
  importOrderSortSpecifiers: true, // for @trivago/prettier-plugin-sort-imports
}

if I delete it, the generated output is fine. (for me) there's something about having this particular plugin there. Things work if I remove it. It seems to pick up the prettier config if it exists at all. The option to pass a prettier config is just overrides (i think) as it seems to keep using my default one). The code seems to make heavy use of pretty formatting everything. I may need to rename it to a non-default one.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants