quicktype-core 23.0.32 → 23.0.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,6 +37,54 @@ exports.rustOptions = {
37
37
  edition2018: new RendererOptions_1.BooleanOption("edition-2018", "Edition 2018", true),
38
38
  leadingComments: new RendererOptions_1.BooleanOption("leading-comments", "Leading Comments", true)
39
39
  };
40
+ const namingStyles = {
41
+ "snake_case": {
42
+ regex: /^[a-z][a-z0-9]*(_[a-z0-9]+)*$/,
43
+ toParts: (name) => name.split('_'),
44
+ fromParts: (parts) => parts.map(p => p.toLowerCase()).join('_'),
45
+ },
46
+ "SCREAMING_SNAKE_CASE": {
47
+ regex: /^[A-Z][A-Z0-9]*(_[A-Z0-9]+)*$/,
48
+ toParts: (name) => name.split('_'),
49
+ fromParts: (parts) => parts.map(p => p.toUpperCase()).join('_'),
50
+ },
51
+ "camelCase": {
52
+ regex: /^[a-z]+([A-Z0-9][a-z]*)*$/,
53
+ toParts: (name) => namingStyles.snake_case.toParts(name.replace(/(.)([A-Z])/g, "$1_$2")),
54
+ fromParts: (parts) => parts
55
+ .map((p, i) => i === 0
56
+ ? p.toLowerCase()
57
+ : p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase())
58
+ .join(''),
59
+ },
60
+ "PascalCase": {
61
+ regex: /^[A-Z][a-z]*([A-Z0-9][a-z]*)*$/,
62
+ toParts: (name) => namingStyles.snake_case.toParts(name.replace(/(.)([A-Z])/g, "$1_$2")),
63
+ fromParts: (parts) => parts
64
+ .map(p => p.substring(0, 1).toUpperCase() + p.substring(1).toLowerCase())
65
+ .join(''),
66
+ },
67
+ "kebab-case": {
68
+ regex: /^[a-z][a-z0-9]*(-[a-z0-9]+)*$/,
69
+ toParts: (name) => name.split('-'),
70
+ fromParts: (parts) => parts.map(p => p.toLowerCase()).join('-'),
71
+ },
72
+ "SCREAMING-KEBAB-CASE": {
73
+ regex: /^[A-Z][A-Z0-9]*(-[A-Z0-9]+)*$/,
74
+ toParts: (name) => name.split('-'),
75
+ fromParts: (parts) => parts.map(p => p.toUpperCase()).join('-'),
76
+ },
77
+ "lowercase": {
78
+ regex: /^[a-z][a-z0-9]*$/,
79
+ toParts: (name) => [name],
80
+ fromParts: (parts) => parts.map(p => p.toLowerCase()).join(''),
81
+ },
82
+ "UPPERCASE": {
83
+ regex: /^[A-Z][A-Z0-9]*$/,
84
+ toParts: (name) => [name],
85
+ fromParts: (parts) => parts.map(p => p.toUpperCase()).join(''),
86
+ },
87
+ };
40
88
  class RustTargetLanguage extends TargetLanguage_1.TargetLanguage {
41
89
  makeRenderer(renderContext, untypedOptionValues) {
42
90
  return new RustRenderer(this, renderContext, (0, RendererOptions_1.getOptionValues)(exports.rustOptions, untypedOptionValues));
@@ -211,10 +259,12 @@ class RustRenderer extends ConvenienceRenderer_1.ConvenienceRenderer {
211
259
  const isCycleBreaker = this.isCycleBreakerType(t);
212
260
  return isCycleBreaker ? ["Box<", rustType, ">"] : rustType;
213
261
  }
214
- emitRenameAttribute(propName, jsonName) {
262
+ emitRenameAttribute(propName, jsonName, defaultNamingStyle, preferedNamingStyle) {
215
263
  const escapedName = rustStringEscape(jsonName);
216
- const namesDiffer = this.sourcelikeToString(propName) !== escapedName;
217
- if (namesDiffer || this._options.density === Density.Normal) {
264
+ const name = namingStyles[defaultNamingStyle].fromParts(this.sourcelikeToString(propName).split(" "));
265
+ const styledName = nameToNamingStyle(name, preferedNamingStyle);
266
+ const namesDiffer = escapedName !== styledName;
267
+ if (namesDiffer) {
218
268
  this.emitLine('#[serde(rename = "', escapedName, '")]');
219
269
  }
220
270
  }
@@ -230,10 +280,21 @@ class RustRenderer extends ConvenienceRenderer_1.ConvenienceRenderer {
230
280
  emitStructDefinition(c, className) {
231
281
  this.emitDescription(this.descriptionForType(c));
232
282
  this.emitLine("#[derive(", this._options.deriveDebug ? "Debug, " : "", this._options.deriveClone ? "Clone, " : "", "Serialize, Deserialize)]");
283
+ // List the possible naming styles for every class property
284
+ const propertiesNamingStyles = {};
285
+ this.forEachClassProperty(c, "none", (_name, jsonName, _prop) => {
286
+ propertiesNamingStyles[jsonName] = listMatchingNamingStyles(jsonName);
287
+ });
288
+ // Set the default naming style on the struct
289
+ const defaultStyle = "snake_case";
290
+ const preferedNamingStyle = getPreferedNamingStyle(Object.values(propertiesNamingStyles).flat(), defaultStyle);
291
+ if (preferedNamingStyle !== defaultStyle) {
292
+ this.emitLine(`#[serde(rename_all = "${preferedNamingStyle}")]`);
293
+ }
233
294
  const blankLines = this._options.density === Density.Dense ? "none" : "interposing";
234
295
  const structBody = () => this.forEachClassProperty(c, blankLines, (name, jsonName, prop) => {
235
296
  this.emitDescription(this.descriptionForClassProperty(c, jsonName));
236
- this.emitRenameAttribute(name, jsonName);
297
+ this.emitRenameAttribute(name, jsonName, defaultStyle, preferedNamingStyle);
237
298
  this.emitLine(this.visibility, name, ": ", this.breakCycle(prop.type, true), ",");
238
299
  });
239
300
  this.emitBlock(["pub struct ", className], structBody);
@@ -261,9 +322,20 @@ class RustRenderer extends ConvenienceRenderer_1.ConvenienceRenderer {
261
322
  emitEnumDefinition(e, enumName) {
262
323
  this.emitDescription(this.descriptionForType(e));
263
324
  this.emitLine("#[derive(", this._options.deriveDebug ? "Debug, " : "", this._options.deriveClone ? "Clone, " : "", "Serialize, Deserialize)]");
325
+ // List the possible naming styles for every enum case
326
+ const enumCasesNamingStyles = {};
327
+ this.forEachEnumCase(e, "none", (_name, jsonName) => {
328
+ enumCasesNamingStyles[jsonName] = listMatchingNamingStyles(jsonName);
329
+ });
330
+ // Set the default naming style on the enum
331
+ const defaultStyle = "PascalCase";
332
+ const preferedNamingStyle = getPreferedNamingStyle(Object.values(enumCasesNamingStyles).flat(), defaultStyle);
333
+ if (preferedNamingStyle !== defaultStyle) {
334
+ this.emitLine(`#[serde(rename_all = "${preferedNamingStyle}")]`);
335
+ }
264
336
  const blankLines = this._options.density === Density.Dense ? "none" : "interposing";
265
337
  this.emitBlock(["pub enum ", enumName], () => this.forEachEnumCase(e, blankLines, (name, jsonName) => {
266
- this.emitRenameAttribute(name, jsonName);
338
+ this.emitRenameAttribute(name, jsonName, defaultStyle, preferedNamingStyle);
267
339
  this.emitLine([name, ","]);
268
340
  }));
269
341
  }
@@ -304,9 +376,35 @@ class RustRenderer extends ConvenienceRenderer_1.ConvenienceRenderer {
304
376
  this.emitLine("use std::collections::HashMap;");
305
377
  }
306
378
  this.forEachTopLevel("leading", (t, name) => this.emitTopLevelAlias(t, name), t => this.namedTypeToNameForTopLevel(t) === undefined);
307
- this.forEachObject("leading-and-interposing", (c, name) => this.emitStructDefinition(c, name));
308
- this.forEachUnion("leading-and-interposing", (u, name) => this.emitUnion(u, name));
309
- this.forEachEnum("leading-and-interposing", (e, name) => this.emitEnumDefinition(e, name));
379
+ this.forEachNamedType("leading-and-interposing", (c, name) => this.emitStructDefinition(c, name), (e, name) => this.emitEnumDefinition(e, name), (u, name) => this.emitUnion(u, name));
310
380
  }
311
381
  }
312
382
  exports.RustRenderer = RustRenderer;
383
+ function getPreferedNamingStyle(namingStyleOccurences, defaultStyle) {
384
+ const occurrences = Object.fromEntries(Object.keys(namingStyles).map(key => [key, 0]));
385
+ namingStyleOccurences
386
+ .forEach(style => ++occurrences[style]);
387
+ const max = Math.max(...Object.values(occurrences));
388
+ const preferedStyles = Object.entries(occurrences)
389
+ .filter(([_style, num]) => num === max)
390
+ .map(([style, _num]) => style);
391
+ if (preferedStyles.includes(defaultStyle)) {
392
+ return defaultStyle;
393
+ }
394
+ return preferedStyles[0];
395
+ }
396
+ function listMatchingNamingStyles(name) {
397
+ return Object.entries(namingStyles)
398
+ .filter(([_, { regex }]) => regex.test(name))
399
+ .map(([namingStyle, _]) => namingStyle);
400
+ }
401
+ function nameToNamingStyle(name, style) {
402
+ if (namingStyles[style].regex.test(name)) {
403
+ return name;
404
+ }
405
+ const fromStyle = listMatchingNamingStyles(name)[0];
406
+ if (fromStyle === undefined) {
407
+ return name;
408
+ }
409
+ return namingStyles[style].fromParts(namingStyles[fromStyle].toParts(name));
410
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "quicktype-core",
3
- "version": "23.0.32",
3
+ "version": "23.0.33",
4
4
  "description": "The quicktype engine as a library",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",