Azure / autorest.typescript

Extension for AutoRest (https://github.com/Azure/autorest) that generates TypeScript code. The transpiled javascript code is isomorphic. It can be run in browser and in node.js environment.
MIT License
178 stars 75 forks source link

Normalize enum member name in modular #2832

Open MaryGao opened 1 month ago

MaryGao commented 1 month ago

Currently we directly generate the enum member name as typespec defined. This would be an issue if typespec enum member is not a valid typescript name. And it's better include to normalize them and also normalization could help produce more ts-style SDKs.

https://github.com/Azure/autorest.typescript/blob/ca2912409b91c4adff8f53215567d17c2c8fb5a8/packages/typespec-ts/test/modularIntegration/generated/azure/resource-manager/common-properties/src/index.d.ts#L50-L55

MaryGao commented 1 week ago

Background

For generated enum we need enum member name and value, and the typespec member name may not be a valid typescript name so we need to normalize them and also normalization could help produce more ts-style SDKs.

What is a valid enum member name? Enums are real objects that exist at runtime. Similar to object we could access enum member value via dot-notation e.g EnumA.X or via indexed access types e.g EnumA["X"]. Any literal which is a valid object property could be a valid enum member name expect numeric name e.g "10" or 10.

An enum member cannot have a numeric name.

What is the recommanded style for member name? I think it's better to have PascalCase style for enum member name and this is also style we used in HLC and aligned with the camelCase style for property normalization.

Do we need to ensure all enum member could be dot-notable? I prefer we try our best to do this but there may be situation where it's better to keep original constants other than giving a wired name. For example for float literal "1.2" to make it dot-notable we need to rename as "One2" or "1Dot2" or "12", other than that I would prefer to name it as "Number1.2" and log a warning for names which are not dot-notable. But the bottle line would be generating compile-pass code.

Can we allow users to disable the name normalization? I prefer yes. Similar to property norm we have an option property-name-normalized to disable default normalization. I think we could make this option more generic like name-normalized to disable norms for enum member name. But to generate compile-pass code we still need to handle numeric name.

What if we produce duplicated names? I don't want to introduce a lot complexity from our side. If we produce duplicated names we could guide users to rename the ambiguous names or turn off above option to disable norms.

Will it have breakings for HLC and how to handle them? Yes, we will have breakings for numeric name, and we could use @clientName to avoid this breaking.

Proposals

Enum member name could be arbitrary or numeric. And the process to handle them would be:

  1. If it is a numeric name, return Number${input}.See the explicit logic to detect a numeric name; log a warnning for renaming by clientName decorator;
  2. Else then splitting the input and escape non-(alphabets and numeric digits) chars. See similar logic here.
  3. Then format with PascalCase styles;
  4. Then if the norm name is starting with a digit, add a Number${input} and log a warning for renaming by clientName decorator.
// case 1: pure alphabets
["pascal", "Pascal"],
["pascalCase", "PascalCase"],
["PascalCase", "PascalCase"],
["pascalcase", "Pascalcase"],
["Pascalcase", "Pascalcase"],

// case 2: alphabets + special chars e.g .-*/
["pascal_case", "PascalCase"],
["pascal_case_", "PascalCase"],
["_pascal_case", "PascalCase"],
["pascal, case", "PascalCase"],
["MAX_of_MLD", "MaxOfMld"],

// case 3: alphabets + special chars + digits
["___pascal____case6666", "PascalCase6666"],
["_10Min", "Number10Min"],

// case 4: digits but not a numeric name
["090", "Number090"],

// case 5: digits but valid numeric name
["10", "Number10"],
["1.0", "Number1.0"],
["-1.0", "Number-1.0"],
MaryGao commented 1 week ago

@qiaozha @joheredi Could you help review above design? Thanks!

qiaozha commented 1 week ago

I don't think we can get dot user experience with “10Min” even if can be defined in TypeScript playground

why not just add Number prefix to all enum keys that are started with number? @joheredi how do you think?

MaryGao commented 1 week ago

I don't think we can get dot user experience with “10Min” even if can be defined in TypeScript playground

why not just add Number prefix to all enum keys that are started with number? @joheredi how do you think?

I am okay with adding a prefix with starting with number. I just want to clarify "090", "_090" and "90" are different cases and only the last one "90" is a valid numeric name. The first two would be not. And so any Number prefix is adding after normalizaiton for first two.

Updated the above design with this idea.