Skip to content

Conversation

amustaque97
Copy link
Member

@amustaque97 amustaque97 commented Oct 14, 2025

What does this PR do?

This patch fixes invalid nested double-quote permission tokens that were appearing in generated examples (e.g. permissions: ["read("any")"]), and hardens Web/Deno parameter example rendering so string/array/object examples produce safe JS literals.

  • Web.php Improve getParamExample() so string/array/object examples are JSON encoded / pretty-printed as valid JS literals.
  • Add a targeted fallback to normalize permission-like tokens (convert inner double-quotes to single-quotes) only when necessary.
  • permission.ts.twig Render permission tokens with single quotes (e.g. read('${role}')) to avoid nested double-quotes in generated JS/TS examples.
  • permission.ts.twig Same change as above for Deno templates.

Testing screenshot for reference
Screenshot 2025-10-15 at 4 35 57 PM

(Provide a description of what this PR does.)

Test Plan

(Write your test plan here. If you changed any code, please provide us with clear instructions on how you verified your changes work.)

Related PRs and Issues

(If this PR is related to any other PR or resolves any issue or related to any issue link all related PR and issues here.)

Have you read the Contributing Guidelines on issues?

(Write your answer here.)

Summary by CodeRabbit

  • Bug Fixes

    • Improved formatting of parameter examples: arrays and objects are validated and rendered as proper JSON or pretty-printed objects; booleans output as true/false; numbers and files preserved; strings are safely escaped for correct display.
  • Style

    • Permission string literals now consistently use single quotes around role values across platforms, unifying generated output formatting.

Copy link
Contributor

coderabbitai bot commented Oct 14, 2025

Walkthrough

Replaced match expressions with switch-based logic in multiple SDK language classes (src/SDK/Language/Web.php, Deno.php, Node.php, ReactNative.php) to provide explicit handling for TYPE_ARRAY, TYPE_OBJECT, TYPE_INTEGER/NUMBER, TYPE_FILE, TYPE_BOOLEAN, and TYPE_STRING (including JSON decoding/pretty-printing and permission-token normalization). Adjusted spacing in several arrow functions (getGenerics, getReturn, getSubSchema). Updated permission template outputs (templates/*/permission.ts.twig) to use single quotes around role values. No public API signature changes.

Possibly related PRs

Suggested reviewers

  • abnegate
  • loks0n

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 71.43% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title accurately and concisely describes the primary change of handling nested quotes properly in documentation examples, directly reflecting the updates to permission tokens and JSON‐formatting logic in generated code.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch PLA-3576

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@amustaque97 amustaque97 marked this pull request as ready for review October 15, 2025 11:06
@amustaque97 amustaque97 self-assigned this Oct 15, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
templates/react-native/src/permission.ts.twig (1)

4-4: Switch to single quotes fixes nested-quote breakage — LGTM.

Prevents invalid examples like ["read("any")"]. One caveat: if role can contain a single quote, escape it or ensure upstream never includes it.

Option (optional) to harden:

-        return `read('${role}')`
+        return `read('${role.replace(/'/g, "\\'")}')`

Also applies to: 8-8, 12-12, 16-16, 20-20

templates/deno/src/permission.ts.twig (1)

4-4: Consistent single-quote usage across permissions — looks good.

Same note as RN: escape single quotes in role if possible to avoid malformed permission strings.

Optional hardening:

-        return `read('${role}')`
+        return `read('${role.replace(/'/g, "\\'")}')`

Also applies to: 8-8, 12-12, 16-16, 20-20

templates/web/src/permission.ts.twig (1)

12-12: Good fix; avoids nested double-quotes in docs.

Keeps examples valid in JSON/JS. Consider escaping single quotes in role to cover rare edge cases.

Optional:

-        return `read('${role}')`;
+        return `read('${role.replace(/'/g, "\\'")}')`;

Also applies to: 25-25, 35-35, 45-45, 55-55

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a20b20c and e0bfd27.

📒 Files selected for processing (4)
  • src/SDK/Language/Web.php (4 hunks)
  • templates/deno/src/permission.ts.twig (1 hunks)
  • templates/react-native/src/permission.ts.twig (1 hunks)
  • templates/web/src/permission.ts.twig (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/SDK/Language/Web.php (1)
src/SDK/Language.php (1)
  • toPascalCase (96-99)
🔇 Additional comments (1)
src/SDK/Language/Web.php (1)

309-309: Minor style consistency — good.

Arrow function spacing normalized (fn($x) …). No functional changes.

Also applies to: 342-342, 362-362

Comment on lines +147 to +192
switch ($type) {
case self::TYPE_ARRAY:
// Try to decode JSON array and re-encode to ensure valid JS array literal
if (is_array($example)) {
return json_encode($example, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}

$decoded = json_decode($example, true);
if (null !== $decoded && is_array($decoded)) {
return json_encode($decoded, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}

// Fallback: handle permission-like strings that contain unescaped inner quotes,
// e.g. ["read("any")"] -> ["read('any')"] by converting inner double-quotes to single-quotes
$fixed = preg_replace_callback('/([a-zA-Z_]+)\(\"([^\"]+)\"\)/', function ($m) {
return $m[1] . "('" . $m[2] . "')";
}, $example);

return $fixed ?? $example;

case self::TYPE_INTEGER:
case self::TYPE_NUMBER:
return $example;

case self::TYPE_FILE:
return 'document.getElementById(\'uploader\').files[0]';

case self::TYPE_BOOLEAN:
return ($example) ? 'true' : 'false';

case self::TYPE_OBJECT:
if ($example === '{}') {
return '{}';
}
$decodedObj = json_decode($example, true);
if (null !== $decodedObj && is_array($decodedObj)) {
$formatted = json_encode($decodedObj, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
return preg_replace('/\n/', "\n ", $formatted);
}
return $example;

case self::TYPE_STRING:
default:
// Use json_encode to produce properly quoted and escaped JS string literal
return json_encode((string) $example, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

❓ Verification inconclusive

Robustness gap: TYPE_OBJECT may throw TypeError when example is array/object.

json_decode expects string; passing array/object can error in PHP 8+. Handle non-string examples directly and tighten decoding.

Proposed patch:

         switch ($type) {
             case self::TYPE_ARRAY:
                 // Try to decode JSON array and re-encode to ensure valid JS array literal
                 if (is_array($example)) {
                     return json_encode($example, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
                 }
@@
                 return ($example) ? 'true' : 'false';
 
             case self::TYPE_OBJECT:
-                if ($example === '{}') {
-                    return '{}';
-                }
-                $decodedObj = json_decode($example, true);
-                if (null !== $decodedObj && is_array($decodedObj)) {
-                    $formatted = json_encode($decodedObj, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
-                    return preg_replace('/\n/', "\n    ", $formatted);
-                }
-                return $example;
+                // Accept pre-parsed examples
+                if (is_array($example) || is_object($example)) {
+                    $formatted = json_encode($example, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+                    return preg_replace('/\n/', "\n    ", $formatted);
+                }
+                if ($example === '{}' || \trim((string) $example) === '{}') {
+                    return '{}';
+                }
+                $decodedObj = json_decode((string) $example, true);
+                if (json_last_error() === JSON_ERROR_NONE && is_array($decodedObj)) {
+                    $formatted = json_encode($decodedObj, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
+                    return preg_replace('/\n/', "\n    ", $formatted);
+                }
+                return (string) $example;
 
             case self::TYPE_STRING:
             default:
                 // Use json_encode to produce properly quoted and escaped JS string literal
                 return json_encode((string) $example, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
         }

Also, optional: after fixing inner quotes in TYPE_ARRAY, consider trimming and returning the normalized string (current approach is fine for JS literals).


Handle non-string $example in TYPE_OBJECT to prevent TypeError: In the TYPE_OBJECT case of src/SDK/Language/Web.php, first check is_array($example) || is_object($example) and format with json_encode, then cast $example to string for json_decode and verify json_last_error().

public function getFiles(): array
{
return [
[
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

any reason for removing these files? pretty sure they are needed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was accidentally pushed I'm reverting it. Please review changes for web, deno & react-native.

src/SDK/SDK.php Outdated
}
}

// No post-processing here: per-language getParamExample implementations should
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why was this added?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pushed accidentally, I'm reverting it.

*/
static read = (role: string): string => {
return `read("${role}")`;
return `read('${role}')`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these shoudnt matter no? not related to docs at all


static read = (role: string): string => {
return `read("${role}")`
return `read('${role}')`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, not related


static read = (role: string): string => {
return `read("${role}")`
return `read('${role}')`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here, not related

: (($formatted = json_encode(json_decode($example, true), JSON_PRETTY_PRINT))
? preg_replace('/\n/', "\n ", $formatted)
: $example),
self::TYPE_STRING => "'{$example}'",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we only needed change in type string, any reasons for changing all the others?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (6)
src/SDK/Language/ReactNative.php (2)

231-233: Robust boolean parsing.

String "false" evaluates truthy; current code would output true.

Apply:

-            case self::TYPE_BOOLEAN:
-                return ($example) ? 'true' : 'false';
+            case self::TYPE_BOOLEAN:
+                $bool = is_bool($example) ? $example : filter_var($example, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+                return ($bool === true) ? 'true' : 'false';

206-248: De-duplicate normalization logic across languages.

The ARRAY/OBJECT formatting and permission-token fix are duplicated in Node/Deno. Extract a protected helper (e.g., normalizePermissionTokens(string): string) in a common base to prevent drift.

src/SDK/Language/Deno.php (2)

203-205: Robust boolean parsing.

Avoid treating "false" as truthy.

Apply:

-            case self::TYPE_BOOLEAN:
-                return ($example) ? 'true' : 'false';
+            case self::TYPE_BOOLEAN:
+                $bool = is_bool($example) ? $example : filter_var($example, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+                return ($bool === true) ? 'true' : 'false';

178-220: Centralize shared logic.

Extract the permission-token normalization and JSON pretty-printing into a shared helper to keep Deno/ReactNative/Web/Node aligned.

src/SDK/Language/Node.php (2)

167-169: Robust boolean parsing.

Avoid truthiness pitfalls with "false"/"0".

Apply:

-            case self::TYPE_BOOLEAN:
-                return ($example) ? 'true' : 'false';
+            case self::TYPE_BOOLEAN:
+                $bool = is_bool($example) ? $example : filter_var($example, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
+                return ($bool === true) ? 'true' : 'false';

142-184: Reduce duplication across languages.

The ARRAY/OBJECT handling and permission normalization are shared with Web/Deno/ReactNative; factor into a base helper to keep behavior consistent.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e0bfd27 and 29cf2d5.

📒 Files selected for processing (6)
  • src/SDK/Language/Deno.php (1 hunks)
  • src/SDK/Language/Node.php (3 hunks)
  • src/SDK/Language/ReactNative.php (2 hunks)
  • src/SDK/SDK.php (1 hunks)
  • templates/deno/src/permission.ts.twig (1 hunks)
  • templates/react-native/src/permission.ts.twig (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • src/SDK/SDK.php
🚧 Files skipped from review as they are similar to previous changes (2)
  • templates/deno/src/permission.ts.twig
  • templates/react-native/src/permission.ts.twig
🧰 Additional context used
🧬 Code graph analysis (2)
src/SDK/Language/ReactNative.php (1)
src/SDK/Language.php (1)
  • toPascalCase (96-99)
src/SDK/Language/Node.php (3)
src/SDK/Language.php (2)
  • toPascalCase (96-99)
  • getParamExample (56-56)
src/SDK/Language/Deno.php (1)
  • getParamExample (161-221)
src/SDK/Language/Web.php (1)
  • getParamExample (130-193)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (19)
  • GitHub Check: build (8.3, WebNode)
  • GitHub Check: build (8.3, Python312)
  • GitHub Check: build (8.3, Python313)
  • GitHub Check: build (8.3, Node18)
  • GitHub Check: build (8.3, Ruby27)
  • GitHub Check: kotlin (server)
  • GitHub Check: build (8.3, PHP83)
  • GitHub Check: build (8.3, KotlinJava11)
  • GitHub Check: build (8.3, KotlinJava17)
  • GitHub Check: build (8.3, Android14Java17)
  • GitHub Check: swift (server)
  • GitHub Check: build (8.3, DartBeta)
  • GitHub Check: build (8.3, DotNet60)
  • GitHub Check: build (8.3, Android5Java17)
  • GitHub Check: build (8.3, DartStable)
  • GitHub Check: build (8.3, Go112)
  • GitHub Check: flutter (client)
  • GitHub Check: apple (client)
  • GitHub Check: android (client)
🔇 Additional comments (1)
src/SDK/Language/Node.php (1)

109-109: Formatting-only change.

No behavioral impact.

Comment on lines +189 to +195
// Fallback: normalize permission-like tokens inside array elements
$fixed = preg_replace_callback('/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/', function ($m) {
return $m[1] . "('" . $m[2] . "')";
}, $example);

return $fixed ?? $example;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Escape single quotes in permission-token fallback.

Ensure read("O'Connor") becomes read('O'Connor'), not invalid JS.

Apply:

-                $fixed = preg_replace_callback('/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/', function ($m) {
-                    return $m[1] . "('" . $m[2] . "')";
-                }, $example);
+                $fixed = preg_replace_callback('/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/', function ($m) {
+                    $inner = str_replace("'", "\\'", $m[2]);
+                    return $m[1] . "('{$inner}')";
+                }, (string) $example);

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/SDK/Language/Deno.php around lines 189 to 195, the preg_replace_callback
builds a single-quoted token string but doesn’t escape inner single quotes, so
input like read("O'Connor") becomes invalid JS; update the callback to escape
single quotes in $m[2] before embedding (e.g. replace ' with \' via str_replace
or similar) so the returned string is $m[1] . "('" . <escaped $m[2]> . "')";
keep the rest of the logic unchanged.

Comment on lines 153 to 159
// Fallback for permission-like tokens inside array elements: read("role") -> read('role')
$fixed = preg_replace_callback('/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/', function ($m) {
return $m[1] . "('" . $m[2] . "')";
}, $example);

return $fixed ?? $example;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Escape single quotes in permission-token fallback.

Prevent invalid JS when value contains apostrophes.

Apply:

-                $fixed = preg_replace_callback('/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/', function ($m) {
-                    return $m[1] . "('" . $m[2] . "')";
-                }, $example);
+                $fixed = preg_replace_callback('/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/', function ($m) {
+                    $inner = str_replace("'", "\\'", $m[2]);
+                    return $m[1] . "('{$inner}')";
+                }, (string) $example);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Fallback for permission-like tokens inside array elements: read("role") -> read('role')
$fixed = preg_replace_callback('/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/', function ($m) {
return $m[1] . "('" . $m[2] . "')";
}, $example);
return $fixed ?? $example;
// Fallback for permission-like tokens inside array elements: read("role") -> read('role')
$fixed = preg_replace_callback(
'/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/',
function ($m) {
$inner = str_replace("'", "\\'", $m[2]);
return $m[1] . "('{$inner}')";
},
(string) $example
);
return $fixed ?? $example;
🤖 Prompt for AI Agents
In src/SDK/Language/Node.php around lines 153 to 159, the fallback that converts
double-quoted permission tokens to single-quoted form doesn't escape single
quotes (or backslashes) in the token value, which can produce invalid JS when
the value contains an apostrophe; change the callback to escape backslashes and
single quotes in $m[2] (e.g. replace "\" with "\\\\" and "'" with "\\'") before
embedding it in the returned string so the produced single-quoted JS literal is
safe.

Comment on lines 164 to 166
case self::TYPE_FILE:
return 'document.getElementById(\'uploader\').files[0]';

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Wrong FILE example for NodeJS runtime.

Node examples shouldn’t reference document; use InputFile.fromPath for Node.

Apply:

-            case self::TYPE_FILE:
-                return 'document.getElementById(\'uploader\').files[0]';
+            case self::TYPE_FILE:
+                return 'InputFile.fromPath(\'/path/to/file\', \'filename\')';
🤖 Prompt for AI Agents
In src/SDK/Language/Node.php around lines 164 to 166, the NodeJS example returns
a browser DOM file reference (document.getElementById(...).files[0]) which is
invalid for Node; replace that return value with a Node-friendly InputFile
example such as using InputFile.fromPath('path/to/file') (update any surrounding
example text to reflect a path parameter and mention using InputFile.fromPath
for file uploads in Node).

Comment on lines +217 to +223
// Fallback: normalize permission-like tokens inside array elements
$fixed = preg_replace_callback('/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/', function ($m) {
return $m[1] . "('" . $m[2] . "')";
}, $example);

return $fixed ?? $example;

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Escape single quotes in permission-token fallback.

Values like read("O'Connor") will render invalid JS: read('O'Connor'). Escape inner single quotes and cast $example to string.

Apply:

-                $fixed = preg_replace_callback('/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/', function ($m) {
-                    return $m[1] . "('" . $m[2] . "')";
-                }, $example);
+                $fixed = preg_replace_callback('/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/', function ($m) {
+                    $inner = str_replace("'", "\\'", $m[2]);
+                    return $m[1] . "('{$inner}')";
+                }, (string) $example);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Fallback: normalize permission-like tokens inside array elements
$fixed = preg_replace_callback('/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/', function ($m) {
return $m[1] . "('" . $m[2] . "')";
}, $example);
return $fixed ?? $example;
// Fallback: normalize permission-like tokens inside array elements
$fixed = preg_replace_callback('/([a-zA-Z_][a-zA-Z0-9_]*)\(\s*"([^"\)]*)"\s*\)/', function ($m) {
$inner = str_replace("'", "\\'", $m[2]);
return $m[1] . "('{$inner}')";
}, (string) $example);
return $fixed ?? $example;
🤖 Prompt for AI Agents
In src/SDK/Language/ReactNative.php around lines 217-223, the
preg_replace_callback fallback doesn't escape single quotes and doesn't ensure
$example is a string; update the callback to escape inner single quotes in the
permission token (e.g. replace ' with \') when building the replacement, cast
$example to string when passing it to preg_replace_callback (or at least in the
return), and return the escaped result or (string)$example if no replacement
occurred.

@amustaque97 amustaque97 reopened this Oct 16, 2025
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

Successfully merging this pull request may close these issues.

2 participants