@f3liz/rescript-autogen-openapi 0.3.1 → 0.5.0

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.
@@ -31,6 +31,65 @@ function escapeString(str) {
31
31
  return str.replaceAll("\\", "\\\\").replaceAll("\"", "\\\"").replaceAll("\n", "\\n").replaceAll("\r", "\\r").replaceAll("\t", "\\t");
32
32
  }
33
33
 
34
+ function escapeRegexPattern(str) {
35
+ return (function(s) {
36
+ return s.replace(/\[([^\]]+)\]/g, function(match) {
37
+ let content = match.slice(1, -1);
38
+ let chars = [];
39
+ let hyphenCount = 0;
40
+ let i = 0;
41
+
42
+ while (i < content.length) {
43
+ if (content[i] === '\\\\' && i + 1 < content.length) {
44
+ if (content[i + 1] === '-') {
45
+ // Escaped hyphen - count it and skip
46
+ hyphenCount++;
47
+ i += 2;
48
+ } else {
49
+ // Other escaped char - keep as is
50
+ chars.push(content[i]);
51
+ chars.push(content[i + 1]);
52
+ i += 2;
53
+ }
54
+ } else if (content[i] === '-' && i > 0 && i < content.length - 1) {
55
+ // Check if this hyphen is part of a valid range
56
+ let prevChar = chars[chars.length - 1];
57
+ let nextChar = content[i + 1];
58
+ // If previous char is a backslash, this can't be a range
59
+ if (chars.length >= 2 && chars[chars.length - 2] === '\\\\') {
60
+ // Previous was escaped, so this hyphen is literal
61
+ hyphenCount++;
62
+ i++;
63
+ } else if (nextChar === '\\\\') {
64
+ // Next is escape sequence, hyphen is literal
65
+ hyphenCount++;
66
+ i++;
67
+ } else if (prevChar && nextChar && prevChar.charCodeAt(0) < nextChar.charCodeAt(0)) {
68
+ // Valid range (e.g., a-z), keep the hyphen
69
+ chars.push('-');
70
+ i++;
71
+ } else {
72
+ // Invalid or ambiguous, move to end
73
+ hyphenCount++;
74
+ i++;
75
+ }
76
+ } else {
77
+ // Regular character or hyphen at start/end
78
+ chars.push(content[i]);
79
+ i++;
80
+ }
81
+ }
82
+
83
+ // Add collected hyphens at the end
84
+ let result = chars.join('');
85
+ if (hyphenCount > 0) {
86
+ result += '-'.repeat(hyphenCount);
87
+ }
88
+ return '[' + result + ']';
89
+ });
90
+ })(str);
91
+ }
92
+
34
93
  function generateFileHeader(description) {
35
94
  return `// ` + description + `
36
95
  // Generated by @f3liz/rescript-autogen-openapi
@@ -247,6 +306,7 @@ export {
247
306
  generateTypeName,
248
307
  generateOperationName,
249
308
  escapeString,
309
+ escapeRegexPattern,
250
310
  generateFileHeader,
251
311
  indent,
252
312
  trimMargin,
@@ -50,7 +50,7 @@ function generateSchemaWithContext(ctx, depthOpt, extractedTypeMap, irType) {
50
50
  let s = applyConstraints("S.string", c.minLength, c.maxLength, v => v.toString());
51
51
  let p = c.pattern;
52
52
  if (p !== undefined) {
53
- return s + `->S.pattern(%re("/` + CodegenUtils.escapeString(p) + `/"))`;
53
+ return s + `->S.pattern(/` + CodegenUtils.escapeRegexPattern(p) + `/)`;
54
54
  } else {
55
55
  return s;
56
56
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@f3liz/rescript-autogen-openapi",
3
- "version": "0.3.1",
3
+ "version": "0.5.0",
4
4
  "description": "Generate ReScript code with Sury schemas from OpenAPI 3.1 specs. Supports multiple forks with diff/merge capabilities.",
5
5
  "keywords": [
6
6
  "rescript",
@@ -48,6 +48,71 @@ let escapeString = (str: string): string =>
48
48
  ->String.replaceAll("\n", "\\n")->String.replaceAll("\r", "\\r")
49
49
  ->String.replaceAll("\t", "\\t")
50
50
 
51
+ // Escape Regex Pattern for ReScript 12 regex literals
52
+ // With /.../ syntax, forward slashes don't need escaping inside character classes
53
+ // Only fix hyphen placement in character classes for clarity
54
+ let escapeRegexPattern = (str: string): string => {
55
+ // Move escaped hyphens (\-) to the end of character classes for clarity
56
+ %raw(`
57
+ function(s) {
58
+ return s.replace(/\[([^\]]+)\]/g, function(match) {
59
+ let content = match.slice(1, -1);
60
+ let chars = [];
61
+ let hyphenCount = 0;
62
+ let i = 0;
63
+
64
+ while (i < content.length) {
65
+ if (content[i] === '\\\\' && i + 1 < content.length) {
66
+ if (content[i + 1] === '-') {
67
+ // Escaped hyphen - count it and skip
68
+ hyphenCount++;
69
+ i += 2;
70
+ } else {
71
+ // Other escaped char - keep as is
72
+ chars.push(content[i]);
73
+ chars.push(content[i + 1]);
74
+ i += 2;
75
+ }
76
+ } else if (content[i] === '-' && i > 0 && i < content.length - 1) {
77
+ // Check if this hyphen is part of a valid range
78
+ let prevChar = chars[chars.length - 1];
79
+ let nextChar = content[i + 1];
80
+ // If previous char is a backslash, this can't be a range
81
+ if (chars.length >= 2 && chars[chars.length - 2] === '\\\\') {
82
+ // Previous was escaped, so this hyphen is literal
83
+ hyphenCount++;
84
+ i++;
85
+ } else if (nextChar === '\\\\') {
86
+ // Next is escape sequence, hyphen is literal
87
+ hyphenCount++;
88
+ i++;
89
+ } else if (prevChar && nextChar && prevChar.charCodeAt(0) < nextChar.charCodeAt(0)) {
90
+ // Valid range (e.g., a-z), keep the hyphen
91
+ chars.push('-');
92
+ i++;
93
+ } else {
94
+ // Invalid or ambiguous, move to end
95
+ hyphenCount++;
96
+ i++;
97
+ }
98
+ } else {
99
+ // Regular character or hyphen at start/end
100
+ chars.push(content[i]);
101
+ i++;
102
+ }
103
+ }
104
+
105
+ // Add collected hyphens at the end
106
+ let result = chars.join('');
107
+ if (hyphenCount > 0) {
108
+ result += '-'.repeat(hyphenCount);
109
+ }
110
+ return '[' + result + ']';
111
+ });
112
+ }
113
+ `)(str)
114
+ }
115
+
51
116
  // Generate file header
52
117
  let generateFileHeader = (~description: string): string =>
53
118
  `// ${description}
@@ -42,7 +42,7 @@ let rec generateSchemaWithContext = (~ctx: GenerationContext.t, ~depth=0, ~extra
42
42
  | String({constraints: c}) =>
43
43
  let s = applyConstraints("S.string", c.minLength, c.maxLength, v => Int.toString(v))
44
44
  switch c.pattern {
45
- | Some(p) => `${s}->S.pattern(%re("/${CodegenUtils.escapeString(p)}/"))`
45
+ | Some(p) => `${s}->S.pattern(/${CodegenUtils.escapeRegexPattern(p)}/)`
46
46
  | None => s
47
47
  }
48
48
  | Number({constraints: c}) =>