feat: add Google Ads 2024-2025 modern features - #3
Conversation
Add comprehensive support for the latest Google AdSense features: - Auto Ads with AI-powered placement (2024) - Consent Mode v2 for GDPR compliance (required since March 2024) - Ad Intents - new intent-driven ad format - Anchor Ads with collapsible mobile positioning - In-Article, In-Feed, and Multiplex modern ad formats - Non-personalized ads mode for privacy compliance - Enhanced TypeScript type definitions - Updated documentation with comprehensive usage examples Breaking changes: - Upgraded Google AdSense script URLs to use https - Added crossOrigin="anonymous" attribute for better security Version bumped to 0.2.0 to reflect new features.
Summary of ChangesHello @hideokamoto, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly upgrades the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces comprehensive support for modern Google AdSense features, including Auto Ads, Consent Mode v2, and various new ad formats. The changes are well-structured, with new components and types for each feature. The documentation in README.md has been significantly improved with detailed examples. My review focuses on improving code quality and fixing a potential bug. I've identified some dead code, a potential issue with an event handler, and a minor optimization for an inline script.
|
|
||
| // Anchor and Side Rail positioning (2024 feature) | ||
| export type AnchorPosition = 'top' | 'bottom' | 'both'; | ||
| export type SideRailPosition = 'left' | 'right' | 'both'; |
| __html: ` | ||
| window.dataLayer = window.dataLayer || []; | ||
| function gtag(){dataLayer.push(arguments);} | ||
| gtag('consent', 'default', ${JSON.stringify(consentMode)}); | ||
| `, |
There was a problem hiding this comment.
The inline script within dangerouslySetInnerHTML contains unnecessary newlines and whitespace. While this works, it adds a few extra bytes to the HTML payload. For a cleaner and slightly more optimized output, you can format the script as a single line.
__html: `window.dataLayer = window.dataLayer || [];function gtag(){dataLayer.push(arguments);}gtag('consent', 'default', ${JSON.stringify(consentMode)});`,
Update CI workflows to use supported Node.js versions and latest GitHub Actions: - Update Node.js versions from 10.x/12.x/14.x to 18.x/20.x/22.x - Update actions/checkout from v1/v2 to v4 - Update actions/setup-node from v1 to v4 - Add npm caching for faster builds - Remove Windows/macOS matrix to reduce CI time - Switch from yarn to npm commands for consistency - Update package.json engines to require Node.js >=18 This fixes CI failures caused by EOL Node.js versions.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. WalkthroughRewrote README with new project name and feature-centric docs; bumped package to 1.1.0. Added ConsentModeV2, AutoAdsConfig, AnchorPosition and multiple ad components (AutoAdsScript, InArticleAd, InFeedAd, MultiplexAd, AnchorAd, NextGoogleAdsenseScript). Adjusted script/widget load order and added npa/adTest/adChannel attributes. Updated linter rule. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant App as Client App
participant GoogleAdsense as GoogleAdsense (composed)
participant Script as NextGoogleAdsenseScript
participant Widget as GoogleAdsenseWidget
participant AutoScript as AutoAdsScript
participant AdsJS as google ad.js
App->>GoogleAdsense: render <GoogleAdsense client=... npaMode=... />
GoogleAdsense->>Script: render with client, npaMode
Script->>AdsJS: load ad.js (crossorigin when requested)
GoogleAdsense->>Widget: render widget with props (adTest, adChannel, npaMode)
Widget->>Widget: set data-* attributes (data-ad-client, data-ad-slot, data-npa-mode...)
Widget->>AdsJS: trigger ad processing
alt Auto Ads configured
App->>AutoScript: render <AutoAdsScript client=... config=... consentMode=... />
AutoScript->>AdsJS: push auto-ads config into window.adsbygoogle
AutoScript->>Script: optionally inject consent-mode script
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Areas to focus review on:
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/index.tsx (1)
256-277: Avoid overridingwindow.onloadinsideNextGoogleAdsenseScriptAssigning
window.onloadin the Script'sonLoadcallback will clobber any existingwindow.onloadhandler, and it can fail if the load event has already fired before the script finishes loading. Initialize script-dependent code directly inside theonLoadcallback instead;onLoadis script-scoped and fires as soon as that specific script is ready, whereaswindow.onloadfires much later after all page resources and is not ideal for initializing a single third-party library.- onLoad={() => { - if (typeof window !== 'undefined') { - window.onload = () => { - ((window as any).adsbygoogle = - (window as any).adsbygoogle || []).push({}); - }; - } - }} + onLoad={() => { + if (typeof window !== 'undefined') { + (window as any).adsbygoogle = (window as any).adsbygoogle || []; + (window as any).adsbygoogle.push({}); + } + }}
♻️ Duplicate comments (1)
src/index.tsx (1)
20-22: UnusedSideRailPositiontype – consider documenting or removing
SideRailPositionis defined but not used in this file; if it’s meant for a future SideRail component or external consumption, a short comment explaining that intent would help. Otherwise, consider removing it to keep the surface minimal.
🧹 Nitpick comments (3)
src/index.tsx (3)
122-141: Format-specific ad components are consistent; duplication could be reduced
InArticleAd,InFeedAd,MultiplexAd, andAnchorAdall follow a consistentins.adsbygooglepattern and correctly set the expecteddata-ad-*attributes for their formats. There is quite a bit of repeated JSX (client/slot/npaMode wiring and base styles), so if this grows further it might be worth extracting a small shared helper or base component to DRY it up.Also applies to: 143-165, 166-186, 187-207
220-231: Add explanatory comment or linter disable fordangerouslySetInnerHTMLReact documentation recommends using
dangerouslySetInnerHTMLonly when absolutely necessary for trusted content, and this pattern withJSON.stringify(consentMode)meets that requirement for the official gtag Consent Mode snippet. However, the code currently lacks an inline comment or linter disable directive. To make the intent explicit and prevent linter warnings, add either:
- An inline comment explaining this is a controlled, non–user-input script injection (official gtag pattern)
- Or a Biome linter disable comment (e.g.,
// biome-ignore js/noDangerouslySetInnerHtml: official gtag pattern)
233-239: Align AdSense script tag with current Google recommendations and simplify Auto Ads enablementThe web search confirms both patterns are supported, but Google's current recommendations favor
?client=ca-pub-...in the scriptsrcURL for Auto Ads. More importantly, Auto Ads are controlled entirely through the AdSense account UI—your code doesn't need to pushenable_page_level_adsconfig or require a config object. BothAutoAdsScriptandNextGoogleAdsenseScriptcurrently usedata-ad-clientand require config wiring, but this can be simplified:
- Update both script URLs to include
?client=${client}in thesrcinstead of (or in addition to)data-ad-client- Remove the requirement for
config?.enableAutoAdsand theenable_page_level_adspush; Auto Ads activation is handled in the AdSense account settings, not via script configThis aligns with Google's recommended pattern and eliminates unnecessary configuration overhead for consumers.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/index.tsx(4 hunks)
🧰 Additional context used
🪛 ast-grep (0.39.9)
src/index.tsx
[warning] 223-223: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 Biome (2.1.2)
src/index.tsx
[error] 224-224: Avoid passing content using the dangerouslySetInnerHTML prop.
Setting content using code can expose users to cross-site scripting (XSS) attacks
(lint/security/noDangerouslySetInnerHtml)
🔇 Additional comments (3)
src/index.tsx (3)
4-18: Typed API surface for Consent Mode v2 and modern formats looks solidThe new type definitions (
ConsentModeV2,AutoAdsConfig, extendedGoogleAdsenseProps, and the various*AdProps/AutoAdsProps) are well-structured and keep values constrained ('granted' | 'denied', specific formats, etc.), which should make the public API safer and easier to use from TypeScript.Also applies to: 24-40, 42-85
280-285: UpdatedGoogleAdsensecomposition looks goodWrapping
GoogleAdsenseWidgetwithNextGoogleAdsenseScriptand forwardingclient/npaModegives a clear separation between script loading and ad slot rendering, which should simplify usage for consumers.
209-254: Review comment is based on incorrect assumptions about Google AdSense Auto Ads behaviorIncluding the script tag with the client parameter is sufficient to enable Auto Ads; the
adsbygoogle.push({ enable_page_level_ads: true, ... })call is only needed for special cases like pausing requests for consent, requesting non-personalized ads, or using extra options.The code correctly always renders the script tag with
data-ad-client={client}, which automatically enables Auto Ads. The conditionaladsbygoogle.push()call in theonLoadhandler handles optional features (ad density, ad intents) only whenconfig.enableAutoAdsis truthy. Omittingconfigentirely does not prevent Auto Ads from functioning—it simply skips optional configuration tweaks.Likely an incorrect or invalid review comment.
… build Merge main branch (v1.0.0) with Google Ads 2024-2025 modern features. Main branch changes (from v1.0.0): - Migrated from TSDX to Vite build system - Replaced ESLint/Prettier with Biome - Upgraded to React 19 and Next.js 16 - Modernized CI/CD workflows - Improved type definitions and error handling Google Ads features added (bumped to v1.1.0): - Auto Ads with AI-powered placement (2024) - Consent Mode v2 for GDPR compliance (required since March 2024) - Ad Intents - new intent-driven ad format - Anchor Ads with collapsible mobile positioning (2024) - In-Article, In-Feed, and Multiplex modern ad formats - Non-personalized ads mode for privacy compliance - Enhanced TypeScript type definitions Breaking changes: - Minimum Node.js version: 18 → 20.19.0 - Minimum React version: 16 → 19 - Minimum Next.js version: 11 → 16 - Build system: TSDX → Vite - Linter: ESLint/Prettier → Biome Conflict resolutions: - Used Vite-based package.json from main - Preserved all new Google Ads components and types - Merged NextGoogleAdsenseScript improvements (error handling + new params) - Updated Biome config to allow dangerouslySetInnerHTML for Consent Mode v2 - Removed deprecated size.yml workflow
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (1)
src/index.tsx (1)
106-122: Non‑personalized ads attribute name is incorrect (data-npa-modevsdata-npa)The
npaModeprop is currently wired todata-npa-mode, but AdSense expects thenpaflag viadata-npa="1"(or an equivalentnpa=1request parameter). With the current attribute name, the non‑personalized ads signal is likely ignored, so your advertised NPA/privacy behavior won’t actually take effect.This affects all usages:
GoogleAdsenseWidget(Line 120)InArticleAd(Line 143)InFeedAd(Line 166)MultiplexAd(Line 187)AnchorAd(Line 209)AutoAdsScriptscript tag (Line 244)NextGoogleAdsenseScriptscript tag (Line 274)Suggested fix:
- data-npa-mode={npaMode ? '1' : undefined} + data-npa={npaMode ? '1' : undefined}Apply the same change to each of the components and script tags listed above so that
npaModereliably maps to the documented AdSense NPA signal.Please double‑check the expected attribute name and behavior against the latest AdSense documentation before releasing, since this directly impacts GDPR/non‑personalized ad compliance.
Also applies to: 133-143, 155-167, 177-187, 198-209, 244-244, 274-274
🧹 Nitpick comments (1)
biome.json (1)
31-36: Avoid disablingnoDangerouslySetInnerHtmlgloballyTurning the
security.noDangerouslySetInnerHtmlrule off for the entire project weakens your safety net for future changes. Since the current use is a single, controlled consent‑mode script, consider keeping this rule enabled and suppressing it only where necessary (e.g., via a file‑specific override or per‑line ignore) instead of at the global level.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (4)
README.md(2 hunks)biome.json(1 hunks)package.json(1 hunks)src/index.tsx(4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- package.json
🧰 Additional context used
🪛 ast-grep (0.39.9)
src/index.tsx
[warning] 228-228: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 LanguageTool
README.md
[grammar] ~318-~318: Use a hyphen to join words.
Context: ... in /dist, so if you are seeing an out of date component, make sure TSDX is run...
(QB_NEW_EN_HYPHEN)
[grammar] ~318-~318: Use a hyphen to join words.
Context: ... /dist, so if you are seeing an out of date component, make sure TSDX is runnin...
(QB_NEW_EN_HYPHEN)
[grammar] ~334-~334: Ensure spelling is correct
Context: .../ai/size-limit) with npm run size and visulize it with npm run analyze. #### Setup ...
(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)
[style] ~434-~434: Consider shortening or rephrasing this to strengthen your wording.
Context: ...project. To fix that you will need to make changes to thepackage.jsonfile _inside theex...
(MAKE_CHANGES)
[style] ~449-~449: Consider using a different verb for a more formal wording.
Context: ...react-dom" }, ``` An alternative to fixing this problem would be to remove aliases...
(FIX_RESOLVE)
🪛 markdownlint-cli2 (0.18.1)
README.md
295-295: Blank line inside blockquote
(MD028, no-blanks-blockquote)
| ``` | ||
|
|
||
| ### Development Mode | ||
| The default example imports and live reloads whatever is in `/dist`, so if you are seeing an out of date component, make sure TSDX is running in watch mode like we recommend above. **No symlinking required**, we use [Parcel's aliasing](https://parceljs.org/module_resolution.html#aliases). |
There was a problem hiding this comment.
Fix minor README typos and markdown lint issues
Only small documentation nits:
- Line 318: use a hyphen in “out-of-date”.
- Line 334: fix the typo “visulize” → “visualize”.
- Lines 294–297: remove the blank line inside the blockquote to satisfy MD028.
Example patch:
- The default example imports and live reloads whatever is in `/dist`, so if you are seeing an out of date component, make sure TSDX is running in watch mode like we recommend above. **No symlinking required**, we use [Parcel's aliasing](https://parceljs.org/module_resolution.html#aliases).
+ The default example imports and live reloads whatever is in `/dist`, so if you are seeing an out-of-date component, make sure TSDX is running in watch mode like we recommend above. **No symlinking required**, we use [Parcel's aliasing](https://parceljs.org/module_resolution.html#aliases).
- Calculates the real cost of your library using [size-limit](https://github.com/ai/size-limit) with `npm run size` and visulize it with `npm run analyze`.
+ Calculates the real cost of your library using [size-limit](https://github.com/ai/size-limit) with `npm run size` and visualize it with `npm run analyze`.
-> This TSDX setup is meant for developing React component libraries (not apps!) that can be published to NPM. If you’re looking to build a React-based app, you should use `create-react-app`, `razzle`, `nextjs`, `gatsby`, or `react-static`.
-
-> If you’re new to TypeScript and React, checkout [this handy cheatsheet](https://github.com/sw-yx/react-typescript-cheatsheet/)
+> This TSDX setup is meant for developing React component libraries (not apps!) that can be published to NPM. If you’re looking to build a React-based app, you should use `create-react-app`, `razzle`, `nextjs`, `gatsby`, or `react-static`.
+> If you’re new to TypeScript and React, checkout [this handy cheatsheet](https://github.com/sw-yx/react-typescript-cheatsheet/)Also applies to: 334-334, 294-297
🧰 Tools
🪛 LanguageTool
[grammar] ~318-~318: Use a hyphen to join words.
Context: ... in /dist, so if you are seeing an out of date component, make sure TSDX is run...
(QB_NEW_EN_HYPHEN)
[grammar] ~318-~318: Use a hyphen to join words.
Context: ... /dist, so if you are seeing an out of date component, make sure TSDX is runnin...
(QB_NEW_EN_HYPHEN)
🤖 Prompt for AI Agents
In README.md around lines 318, 334, and 294-297, apply three small doc fixes:
change “out of date” to “out-of-date” at line 318, correct the typo “visulize”
to “visualize” at line 334, and remove the stray blank line inside the
blockquote spanning lines 294–297 so the blockquote has no internal blank line
(satisfying MD028).
- 全8コンポーネントのユニットテストを追加 - GoogleAdsenseWidget - InArticleAd - InFeedAd - MultiplexAd - AnchorAd - AutoAdsScript - NextGoogleAdsenseScript - GoogleAdsense - next/scriptのモックを実装 - 各コンポーネントの必須プロパティ、デフォルト値、オプショナルプロパティをテスト - window.adsbygoogleの動作をテスト - 古いblah.test.tsxを削除し、index.test.tsxに統合
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
test/blah.test.tsx(0 hunks)test/index.test.tsx(1 hunks)
💤 Files with no reviewable changes (1)
- test/blah.test.tsx
🧰 Additional context used
🧬 Code graph analysis (1)
test/index.test.tsx (1)
src/index.tsx (8)
GoogleAdsenseWidget(93-125)InArticleAd(128-146)InFeedAd(149-169)MultiplexAd(172-190)AnchorAd(193-212)AutoAdsScript(215-258)NextGoogleAdsenseScript(260-284)GoogleAdsense(286-293)
🪛 ast-grep (0.39.9)
test/index.test.tsx
[warning] 41-41: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🔇 Additional comments (8)
test/index.test.tsx (8)
38-44: Static analysis warning is a false positive.The static analysis tool flagged the
dangerouslySetInnerHTMLusage as a potential XSS risk. However, this is test mock code with fully controlled content (consent mode script from AutoAdsScript), not user-supplied input. This usage is safe and necessary for testing components that inject scripts.
50-136: LGTM!The GoogleAdsenseWidget test suite is comprehensive, covering required props, default values, optional props, and npaMode behavior. React 19 APIs are used correctly with proper cleanup.
138-209: LGTM!The InArticleAd test suite properly validates required props, format/layout attributes, npaMode, and custom styling.
211-271: LGTM!The InFeedAd test suite correctly validates the layoutKey requirement and other ad-specific attributes.
339-411: LGTM!The AnchorAd test suite properly validates default values and the position/collapsible configuration options.
413-517: LGTM!The AutoAdsScript test suite comprehensively covers null returns, script rendering, Consent Mode v2, configuration push behavior, and npaMode. The time-based wait at line 488 aligns with the mocked script loading behavior.
519-628: LGTM!The NextGoogleAdsenseScript test suite is thorough, covering null returns, script rendering, adsbygoogle initialization, and crossOrigin attribute handling (both enabled and disabled). The defensive check at line 574 is reasonable given the async nature of the tests.
630-683: LGTM!The GoogleAdsense composition test suite correctly validates that both child components render and that props are properly forwarded to each component.
| it('applies custom format', () => { | ||
| const div = document.createElement('div'); | ||
| const root = createRoot(div); | ||
| act(() => { | ||
| root.render( | ||
| <MultiplexAd client="ca-pub-123" slot="123456" format="autorelaxed" /> | ||
| ); | ||
| }); | ||
|
|
||
| const ins = div.querySelector('ins'); | ||
| expect(ins?.getAttribute('data-ad-format')).toBe('autorelaxed'); | ||
|
|
||
| act(() => { | ||
| root.unmount(); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Redundant test case.
This test claims to validate "custom format" but uses the same autorelaxed value as the default format test (lines 291-304). This doesn't actually test custom format behavior.
Apply this diff to test a different format value or remove the redundant test:
it('applies custom format', () => {
const div = document.createElement('div');
const root = createRoot(div);
act(() => {
root.render(
- <MultiplexAd client="ca-pub-123" slot="123456" format="autorelaxed" />
+ <MultiplexAd client="ca-pub-123" slot="123456" format="rectangle" />
);
});
const ins = div.querySelector('ins');
- expect(ins?.getAttribute('data-ad-format')).toBe('autorelaxed');
+ expect(ins?.getAttribute('data-ad-format')).toBe('rectangle');
act(() => {
root.unmount();
});
});📝 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.
| it('applies custom format', () => { | |
| const div = document.createElement('div'); | |
| const root = createRoot(div); | |
| act(() => { | |
| root.render( | |
| <MultiplexAd client="ca-pub-123" slot="123456" format="autorelaxed" /> | |
| ); | |
| }); | |
| const ins = div.querySelector('ins'); | |
| expect(ins?.getAttribute('data-ad-format')).toBe('autorelaxed'); | |
| act(() => { | |
| root.unmount(); | |
| }); | |
| }); | |
| it('applies custom format', () => { | |
| const div = document.createElement('div'); | |
| const root = createRoot(div); | |
| act(() => { | |
| root.render( | |
| <MultiplexAd client="ca-pub-123" slot="123456" format="rectangle" /> | |
| ); | |
| }); | |
| const ins = div.querySelector('ins'); | |
| expect(ins?.getAttribute('data-ad-format')).toBe('rectangle'); | |
| act(() => { | |
| root.unmount(); | |
| }); | |
| }); |
🤖 Prompt for AI Agents
In test/index.test.tsx around lines 306 to 321, the "applies custom format" test
is redundant because it uses the same 'autorelaxed' value as the default-format
test; update the test to use a different format (for example 'fluid' or
'rectangle') and assert that the rendered <ins> has data-ad-format equal to that
new value (or alternatively remove the entire test if you prefer to keep only
the default-format case).
Add comprehensive support for the latest Google AdSense features:
Breaking changes:
Version bumped to 0.2.0 to reflect new features.
Summary by CodeRabbit
New Features
Documentation
Tests
Chores