chrome-devtools-frontend 1.0.1717709 → 1.0.1721762
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.
- package/.agents/rules/models-and-core/core-ai-agent-context-and-prompt-discipline.md +29 -0
- package/.agents/rules/models-and-core/core-cdp-and-extension-error-handling.md +34 -0
- package/.agents/rules/models-and-core/core-gn-build-and-module-layering.md +23 -0
- package/.agents/rules/models-and-core/core-runtime-neutrality-and-platform-utils.md +28 -0
- package/.agents/rules/models-and-core/core-sdk-model-and-target-lifecycle.md +35 -0
- package/.agents/rules/models-and-core/core-security-origin-and-capability-guards.md +33 -0
- package/.agents/rules/models-and-core/core-settings-and-storage-migration.md +31 -0
- package/.agents/rules/models-and-core/core-sourcemap-and-workspace-mapping.md +28 -0
- package/.agents/rules/models-and-core/core-trace-engine-handler-invariants.md +32 -0
- package/.agents/rules/models-and-core/core-trace-insight-models-and-timing-types.md +28 -0
- package/.agents/rules/tests/test-cleanup-mutated-globals-and-widgets.md +40 -0
- package/.agents/rules/tests/test-deterministic-async-synchronization.md +30 -0
- package/.agents/rules/tests/test-modular-hooks-and-test-universe.md +38 -0
- package/.agents/rules/tests/test-public-api-and-encapsulation.md +30 -0
- package/.agents/rules/tests/test-shared-fixture-and-helper-reuse.md +29 -0
- package/.agents/rules/tests/test-single-responsibility-and-conciseness.md +37 -0
- package/.agents/rules/tests/test-strict-assertions-and-literal-expectations.md +31 -0
- package/.agents/rules/tests/test-type-safe-mocks-and-events.md +30 -0
- package/.agents/rules/tests/test-view-and-presenter-isolation.md +32 -0
- package/.agents/rules/ui-and-widgets/ui-accessibility-and-semantic-html.md +32 -0
- package/.agents/rules/ui-and-widgets/ui-await-update-complete-post-render.md +30 -0
- package/.agents/rules/ui-and-widgets/ui-css-scoping-and-flex-layout.md +27 -0
- package/.agents/rules/ui-and-widgets/ui-declarative-child-widget-composition.md +29 -0
- package/.agents/rules/ui-and-widgets/ui-lit-declarative-templates-and-directives.md +33 -0
- package/.agents/rules/ui-and-widgets/ui-localization-and-uistrings-hygiene.md +36 -0
- package/.agents/rules/ui-and-widgets/ui-modern-component-and-encapsulation-standards.md +32 -0
- package/.agents/rules/ui-and-widgets/ui-panel-and-meta-registration.md +35 -0
- package/.agents/rules/ui-and-widgets/ui-performance-and-flamechart-rendering.md +34 -0
- package/.agents/rules/ui-and-widgets/ui-pure-view-and-presenter-separation.md +31 -0
- package/.agents/rules/ui-and-widgets/ui-reactive-widget-update-lifecycle.md +34 -0
- package/.agents/rules/ui-and-widgets/ui-security-and-output-sanitization.md +28 -0
- package/.agents/rules/ui-and-widgets/ui-type-safety-and-exhaustiveness.md +37 -0
- package/.agents/rules/ui-and-widgets/ui-view-output-and-callback-contracts.md +35 -0
- package/.agents/rules/ui-and-widgets/ui-visual-logging-instrumentation.md +29 -0
- package/.agents/rules/ui-and-widgets/ui-weak-dom-references-and-observer-cleanup.md +29 -0
- package/.agents/rules/ui-and-widgets/ui-widget-dom-and-listener-lifecycle.md +38 -0
- package/.agents/skills/code-review/SKILL.md +3 -0
- package/.agents/skills/devtools-testing-guidance/SKILL.md +1 -0
- package/.agents/skills/review-models-core/SKILL.md +73 -0
- package/.agents/skills/review-tests/SKILL.md +67 -0
- package/.agents/skills/review-ui-widgets/SKILL.md +115 -0
- package/.agents/skills/ui-eng-vision-local-lit-renderer/SKILL.md +19 -3
- package/.agents/skills/ui-eng-vision-widget-promoter/SKILL.md +2 -1
- package/.agents/skills/ui-widgets/SKILL.md +3 -1
- package/AUTHORS +3 -0
- package/DIR_METADATA +51 -1
- package/eslint.config.mjs +63 -21
- package/front_end/core/platform/api/HostRuntime.ts +1 -0
- package/front_end/core/platform/browser/HostRuntime.ts +10 -0
- package/front_end/core/platform/node/HostRuntime.ts +1 -0
- package/front_end/core/sdk/CSSMatchedStyles.ts +60 -20
- package/front_end/core/sdk/CSSProperty.ts +2 -2
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +28 -9
- package/front_end/core/sdk/NetworkManager.ts +9 -3
- package/front_end/core/sdk/OverlayModel.ts +2 -8
- package/front_end/core/sdk/PrivateVerificationTokensModel.ts +79 -0
- package/front_end/core/sdk/SecurityOrigin.ts +1 -1
- package/front_end/core/sdk/SourceMapCache.ts +20 -15
- package/front_end/core/sdk/SourceMapManager.ts +28 -9
- package/front_end/core/sdk/TargetManager.ts +7 -4
- package/front_end/core/sdk/WebAuthnModel.ts +11 -2
- package/front_end/core/sdk/sdk.ts +2 -0
- package/front_end/entrypoints/inspector_main/InspectorMain.ts +0 -2
- package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +10 -0
- package/front_end/entrypoints/main/GlobalAiButton.ts +1 -1
- package/front_end/entrypoints/main/MainImpl.ts +5 -2
- package/front_end/foundation/Universe.ts +1 -1
- package/front_end/generated/Deprecation.ts +4 -0
- package/front_end/generated/InspectorBackendCommands.ts +3 -3
- package/front_end/generated/SupportedCSSProperties.ts +89 -17
- package/front_end/generated/protocol-mapping.d.ts +1 -0
- package/front_end/generated/protocol-proxy-api.d.ts +1 -0
- package/front_end/generated/protocol.ts +5 -3
- package/front_end/models/{ai_assistance → ai-utils}/AiHistoryStorage.ts +6 -5
- package/front_end/models/{ai_assistance → ai-utils}/AiUtils.ts +9 -0
- package/front_end/models/{ai_assistance → ai-utils}/BuiltInAi.ts +1 -1
- package/front_end/models/ai-utils/ai-utils.ts +17 -0
- package/front_end/models/ai_assistance/AiAgent2.ts +3 -1
- package/front_end/models/ai_assistance/AiConversation.ts +34 -22
- package/front_end/models/ai_assistance/AlwaysAllowedTools.ts +107 -0
- package/front_end/models/ai_assistance/ConversationSummary.ts +2 -1
- package/front_end/models/ai_assistance/PerformanceAnnotations.ts +3 -1
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +3 -1
- package/front_end/models/ai_assistance/agents/AiAgent.ts +15 -7
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +3 -1
- package/front_end/models/ai_assistance/agents/ExecuteJavascript.ts +3 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.snapshot.txt +1 -1
- package/front_end/models/ai_assistance/agents/PerformanceAgent.ts +3 -1
- package/front_end/models/ai_assistance/ai_assistance.ts +9 -10
- package/front_end/models/ai_assistance/data_formatters/FileFormatter.ts +27 -6
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +3 -3
- package/front_end/models/ai_assistance/skills/sources.md +3 -1
- package/front_end/models/ai_assistance/tools/ExecuteJavaScript.ts +1 -0
- package/front_end/models/ai_assistance/tools/GetCookieValues.ts +1 -0
- package/front_end/models/ai_assistance/tools/GetInsightDetails.ts +3 -1
- package/front_end/models/ai_assistance/tools/GetSourceContent.ts +46 -4
- package/front_end/models/ai_assistance/tools/GetStorageValues.ts +1 -0
- package/front_end/models/ai_assistance/tools/Tool.ts +6 -0
- package/front_end/models/breakpoints/BreakpointManager.ts +0 -4
- package/front_end/models/change_tracker/ChangeTracker.ts +2 -0
- package/front_end/models/comment_manager/CommentManager.ts +12 -0
- package/front_end/models/comment_manager/CommentThread.ts +21 -1
- package/front_end/models/elements/ChangeTrackingUtils.ts +37 -0
- package/front_end/models/elements/DOMChanges.ts +24 -36
- package/front_end/models/elements/StyleChanges.ts +97 -0
- package/front_end/models/elements/elements.ts +4 -0
- package/front_end/models/emulation/DeviceModeModel.ts +19 -0
- package/front_end/models/javascript_metadata/NativeFunctions.ts +11 -1
- package/front_end/models/trace/EventsSerializer.ts +35 -2
- package/front_end/models/trace/handlers/LayoutShiftsHandler.ts +17 -21
- package/front_end/models/trace/helpers/SyntheticEvents.ts +4 -2
- package/front_end/models/trace/lantern/core/NetworkAnalyzer.ts +12 -8
- package/front_end/models/trace/types/File.ts +20 -3
- package/front_end/models/trace/types/TraceEvents.ts +8 -3
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +14 -0
- package/front_end/panels/ai_assistance/README.md +1 -1
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +1 -1
- package/front_end/panels/ai_assistance/ai_assistance.ts +2 -0
- package/front_end/panels/ai_assistance/components/ChatInput.ts +5 -43
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +52 -147
- package/front_end/panels/ai_assistance/components/ChatView.ts +28 -3
- package/front_end/panels/ai_assistance/components/PermissionPrompt.ts +151 -0
- package/front_end/panels/ai_assistance/components/RelevantDataDisclaimer.ts +73 -0
- package/front_end/panels/ai_assistance/components/chatInput.css +0 -59
- package/front_end/panels/ai_assistance/components/chatMessage.css +0 -47
- package/front_end/panels/ai_assistance/components/chatView.css +5 -30
- package/front_end/panels/ai_assistance/components/permissionPrompt.css +55 -0
- package/front_end/panels/ai_assistance/components/relevantDataDisclaimer.css +35 -0
- package/front_end/panels/application/ApplicationPanelSidebar.ts +3 -7
- package/front_end/panels/application/BackgroundServiceView.ts +8 -8
- package/front_end/panels/application/IndexedDBViews.ts +102 -73
- package/front_end/panels/application/OpenedWindowDetailsView.ts +167 -130
- package/front_end/panels/application/ServiceWorkerCacheViews.ts +288 -346
- package/front_end/panels/application/StorageBucketsTreeElement.ts +22 -27
- package/front_end/panels/application/StorageItemsToolbar.ts +2 -2
- package/front_end/panels/application/components/StorageMetadataView.ts +207 -160
- package/front_end/panels/application/openedWindowDetailsView.css +7 -30
- package/front_end/panels/application/preloading/components/UsedPreloadingView.ts +1 -1
- package/front_end/panels/changes/changesView.css +0 -6
- package/front_end/panels/console/ConsoleInsightTeaser.ts +5 -1
- package/front_end/panels/console/ConsolePinPane.ts +1 -1
- package/front_end/panels/console/ConsoleView.ts +1 -0
- package/front_end/panels/elements/CSSValueTraceView.ts +5 -5
- package/front_end/panels/elements/ColorSwatchPopoverIcon.ts +14 -6
- package/front_end/panels/elements/ComputedStyleWidget.ts +14 -5
- package/front_end/panels/elements/DOMTreeElementWidget.ts +2 -2
- package/front_end/panels/elements/DOMTreeWidget.ts +7 -3
- package/front_end/panels/elements/EventListenersWidget.ts +1 -1
- package/front_end/panels/elements/LayersWidget.ts +1 -1
- package/front_end/panels/elements/PropertyRenderer.ts +91 -16
- package/front_end/panels/elements/StandaloneStylesContainer.ts +33 -6
- package/front_end/panels/elements/StylePropertiesSection.ts +1 -0
- package/front_end/panels/elements/StylePropertyTreeElement.ts +211 -121
- package/front_end/panels/elements/StylesContainer.ts +2 -0
- package/front_end/panels/elements/StylesSidebarPane.ts +34 -16
- package/front_end/panels/elements/components/QueryContainer.ts +1 -1
- package/front_end/panels/elements/elementStatePaneWidget.css +1 -1
- package/front_end/panels/elements/stylePropertiesTreeOutline.css +1 -1
- package/front_end/panels/elements/stylesSidebarPane.css +4 -0
- package/front_end/panels/emulation/DeviceModeToolbar.ts +57 -25
- package/front_end/panels/emulation/DeviceModeView.ts +27 -1
- package/front_end/panels/emulation/InspectedPagePlaceholder.ts +6 -0
- package/front_end/panels/emulation/MediaQueryInspector.ts +14 -4
- package/front_end/panels/explain/components/ConsoleInsight.ts +2 -3
- package/front_end/panels/explain/explain-meta.ts +1 -1
- package/front_end/panels/issues/AffectedMetadataAllowedSitesView.ts +67 -34
- package/front_end/panels/issues/issues.ts +2 -0
- package/front_end/panels/layer_viewer/LayerTreeOutline.ts +7 -3
- package/front_end/panels/lighthouse/LighthouseController.ts +1 -1
- package/front_end/panels/media/PlayerMessagesView.ts +1 -1
- package/front_end/panels/mobile_throttling/CPUThrottlingSelector.ts +1 -1
- package/front_end/panels/mobile_throttling/NetworkThrottlingSelector.ts +45 -15
- package/front_end/panels/mobile_throttling/ThrottlingManager.ts +3 -3
- package/front_end/panels/network/BinaryResourceView.ts +54 -50
- package/front_end/panels/network/RequestHeadersView.ts +6 -2
- package/front_end/panels/network/RequestPreviewView.ts +28 -5
- package/front_end/panels/network/ResourceWebSocketFrameView.ts +1 -0
- package/front_end/panels/network/components/EditableSpan.ts +11 -30
- package/front_end/panels/network/components/HeaderSectionRow.ts +2 -2
- package/front_end/panels/performance_monitor/PerformanceMonitor.ts +10 -6
- package/front_end/panels/profiler/HeapDetachedElementsView.ts +112 -22
- package/front_end/panels/profiler/HeapProfileView.ts +3 -3
- package/front_end/panels/profiler/HeapSnapshotView.ts +12 -2
- package/front_end/panels/profiler/HeapTimelineOverview.ts +16 -2
- package/front_end/panels/profiler/profiler.ts +0 -2
- package/front_end/panels/protocol_monitor/JSONEditor.ts +1 -1
- package/front_end/panels/protocol_monitor/ProtocolMonitor.ts +1 -1
- package/front_end/panels/recorder/CreateRecordingView.ts +1 -1
- package/front_end/panels/recorder/RecordingView.ts +3 -3
- package/front_end/panels/recorder/ReplaySection.ts +1 -1
- package/front_end/panels/screencast/ScreencastApp.ts +83 -57
- package/front_end/panels/screencast/screencastView.css +1 -1
- package/front_end/panels/settings/AISettingsTab.ts +107 -4
- package/front_end/panels/settings/aiSettingsTab.css +53 -0
- package/front_end/panels/settings/settings-meta.ts +1 -1
- package/front_end/panels/settings/settingsScreen.css +0 -4
- package/front_end/panels/sources/BreakpointsView.ts +2 -2
- package/front_end/panels/sources/DebuggerPlugin.ts +7 -0
- package/front_end/panels/sources/NavigatorView.ts +61 -18
- package/front_end/panels/sources/SourcesNavigator.ts +22 -7
- package/front_end/panels/sources/SourcesPanel.ts +1 -0
- package/front_end/panels/timeline/README.md +12 -0
- package/front_end/panels/timeline/StatusDialog.ts +1 -1
- package/front_end/panels/timeline/ThirdPartyTreeView.ts +1 -3
- package/front_end/panels/timeline/TimelineCommentController.ts +346 -0
- package/front_end/panels/timeline/TimelineDetailsView.ts +24 -1
- package/front_end/panels/timeline/TimelineFlameChartDataProvider.ts +34 -30
- package/front_end/panels/timeline/TimelineFlameChartView.ts +22 -1
- package/front_end/panels/timeline/TimelinePanel.ts +12 -5
- package/front_end/panels/timeline/TimelineTreeView.ts +28 -6
- package/front_end/panels/timeline/components/LiveMetricsView.ts +1 -1
- package/front_end/panels/timeline/components/fieldSettingsDialog.css +2 -2
- package/front_end/panels/timeline/components/insights/baseInsightComponent.css +1 -1
- package/front_end/panels/timeline/overlays/components/entriesLinkOverlay.css +2 -2
- package/front_end/panels/timeline/overlays/components/entryLabelOverlay.css +9 -9
- package/front_end/panels/timeline/timeline-meta.ts +2 -2
- package/front_end/panels/timeline/timeline.ts +4 -0
- package/front_end/panels/timeline/timelineFlamechartPopover.css +2 -2
- package/front_end/panels/timeline/timelinePanel.css +2 -2
- package/front_end/panels/web_audio/WebAudioView.ts +7 -4
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/codemirror.next/chunk/angular.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/angular.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/codemirror.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/cpp.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/cpp.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/java.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/java.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/less.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/less.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/markdown.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/markdown.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/php.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/php.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/python.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/python.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/sass.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/sass.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/svelte.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/svelte.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/vue.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/vue.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/wast.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/wast.js.map +1 -1
- package/front_end/third_party/codemirror.next/chunk/xml.js +1 -1
- package/front_end/third_party/codemirror.next/chunk/xml.js.map +1 -1
- package/front_end/third_party/codemirror.next/codemirror.next.js +1 -1
- package/front_end/third_party/codemirror.next/rollup.config.mjs +1 -1
- package/front_end/tsconfig.json +1 -1
- package/front_end/ui/comments/CommentAnchorResolver.ts +1 -1
- package/front_end/ui/components/buttons/Button.ts +29 -18
- package/front_end/ui/components/code_highlighter/CodeHighlighter.ts +1 -1
- package/front_end/ui/components/dialogs/TypeToAllowDialog.ts +94 -39
- package/front_end/ui/components/dialogs/dialog.css +1 -1
- package/front_end/ui/components/menus/menuItem.css +11 -0
- package/front_end/ui/components/text_editor/AccessiblePlaceholder.ts +1 -1
- package/front_end/ui/components/text_editor/AiCodeCompletionTeaser.ts +1 -1
- package/front_end/ui/components/text_editor/config.ts +2 -1
- package/front_end/ui/components/text_editor/javascript.ts +2 -1
- package/front_end/ui/legacy/InspectorView.ts +4 -2
- package/front_end/ui/legacy/SplitWidget.ts +14 -16
- package/front_end/ui/legacy/TabbedPane.ts +9 -1
- package/front_end/ui/legacy/UIUtils.ts +60 -40
- package/front_end/ui/legacy/components/color_picker/spectrum.css +2 -2
- package/front_end/ui/legacy/components/data_grid/dataGrid.css +9 -0
- package/front_end/ui/legacy/components/inline_editor/CSSAngle.ts +0 -1
- package/front_end/ui/legacy/components/inline_editor/cssShadowEditor.css +5 -7
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +1 -1
- package/front_end/ui/legacy/components/perf_ui/PieChart.ts +11 -0
- package/front_end/ui/legacy/components/perf_ui/chartViewport.css +4 -4
- package/front_end/ui/legacy/components/quick_open/filteredListWidget.css +6 -0
- package/front_end/ui/legacy/components/settings_ui/SettingsUI.ts +1 -1
- package/front_end/ui/legacy/components/source_frame/SourceFrame.ts +38 -13
- package/front_end/ui/legacy/dropTarget.css +1 -1
- package/front_end/ui/legacy/statusBar.css +7 -0
- package/front_end/ui/legacy/tabbedPane.css +0 -7
- package/front_end/ui/visual_logging/KnownContextValues.ts +13 -0
- package/inspector_overlay/main.ts +2 -15
- package/inspector_overlay/tool_persistent.ts +0 -14
- package/mcp/mcp.ts +3 -0
- package/package.json +1 -1
- package/front_end/panels/ai_assistance/components/StylingAgentMarkdownRenderer.ts +0 -178
- package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +0 -147
- package/front_end/panels/profiler/heapDetachedElementsDataGrid.css +0 -14
- package/front_end/ui/components/legacy_wrapper/LegacyWrapper.ts +0 -62
- package/front_end/ui/components/legacy_wrapper/legacy_wrapper.ts +0 -8
- package/inspector_overlay/tool_green_dev_anchors.css +0 -54
- package/inspector_overlay/tool_green_dev_anchors.ts +0 -164
- /package/front_end/models/{ai_assistance → ai-utils}/AiSetting.ts +0 -0
- /package/front_end/models/{ai_assistance → ai-utils}/debug.ts +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-await-update-complete-post-render
|
|
3
|
+
rubric: correctness
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Await this.updateComplete before executing post-render DOM measurements, focus changes, or scroll adjustments
|
|
8
|
+
- **Look for**: `this.requestUpdate()` followed synchronously by `.focus()`, `.getBoundingClientRect()`, `.scrollIntoView()`, or child widget measurement without `await this.updateComplete`.
|
|
9
|
+
- **Do not flag**: State updates that do not interact with rendered DOM nodes after scheduling the update.
|
|
10
|
+
|
|
11
|
+
**Why.** Because `this.requestUpdate()` schedules rendering asynchronously in a microtask, querying DOM geometry, focusing newly rendered controls, or anchoring popovers immediately after `requestUpdate()` operates on stale pre-render DOM state.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
this.#isEditing = true;
|
|
19
|
+
this.requestUpdate();
|
|
20
|
+
this.#focusEditorInput();
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Good:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
this.#isEditing = true;
|
|
27
|
+
this.requestUpdate();
|
|
28
|
+
await this.updateComplete;
|
|
29
|
+
this.#focusEditorInput();
|
|
30
|
+
```
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-css-scoping-and-flex-layout
|
|
3
|
+
rubric: readability
|
|
4
|
+
severity: nit
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Scope light-DOM stylesheets and align elements using flexbox or grid rather than competing margin and position offsets
|
|
8
|
+
- **Look for**: Unscoped generic selectors in light-DOM `.css` files (or `:host` inside `@scope` blocks instead of `:scope`), or CSS rules combining `vertical-align`, negative `margin-top`, and pixel offsets to center icons and buttons.
|
|
9
|
+
- **Do not flag**: Shadow DOM component stylesheets where `:host` scoping is native.
|
|
10
|
+
|
|
11
|
+
**Why.** Unscoped class or tag selectors in light-DOM widget stylesheets leak across the DevTools document, while combining `vertical-align`, negative margins, and `position: relative` offsets creates brittle layouts that break under font scaling or zoom.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
@scope to (devtools-widget > *) {
|
|
19
|
+
:host { display: block; }
|
|
20
|
+
.action-icon {
|
|
21
|
+
vertical-align: middle;
|
|
22
|
+
margin-top: -2px;
|
|
23
|
+
position: relative;
|
|
24
|
+
bottom: 1px;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-declarative-child-widget-composition
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Compose child UI.Widget instances declaratively in Lit templates using the widget() directive instead of imperative show() calls
|
|
8
|
+
- **Look for**: `new ChildWidget()` followed by `.show(...)` or `.appendChild(child.element)` inside Lit view functions or migrated `performUpdate()` methods instead of `<devtools-widget ${widget(ChildWidget, {...})}></devtools-widget>` (or `${widget(ChildWidget, {...})}`).
|
|
9
|
+
- **Do not flag**: Top-level legacy split widgets or tabbed panes that have not migrated to Lit views.
|
|
10
|
+
|
|
11
|
+
**Why.** Imperatively instantiating child widgets and calling `child.show(container)` inside presenters or views bypasses Lit reconciliation, complicates lifecycle management, and recreates widgets unnecessarily across renders.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const child = new DetailsWidget();
|
|
19
|
+
child.data = input.data;
|
|
20
|
+
child.show(target.querySelector('.container')!);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Good:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
Lit.render(html`
|
|
27
|
+
<devtools-widget ${UI.Widget.widget(DetailsWidget, {data: input.data})}></devtools-widget>
|
|
28
|
+
`, target);
|
|
29
|
+
```
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-lit-declarative-templates-and-directives
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Use Lit.nothing, repeat with keys, classMap/styleMap, and ifDefined in single-pass declarative templates instead of imperative DOM mutations
|
|
8
|
+
- **Look for**: Ternary branches returning `''` or `undefined` in `html` templates instead of `Lit.nothing`, unkeyed `.map()` on dynamic stateful lists instead of `repeat()`, `ifDefined` omissions on optional attributes, or multiple `Lit.render()` calls mutating the same container.
|
|
9
|
+
- **Do not flag**: Static arrays of primitive labels where item identity never reorders.
|
|
10
|
+
|
|
11
|
+
**Why.** Mutating DOM elements via `appendChild`, `classList.toggle`, or `innerHTML` alongside Lit templates, or returning `''`/`null` instead of `Lit.nothing` in conditional branches, corrupts Lit's part tracking and creates unnecessary text nodes or wrapper `<div>`s.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
html`
|
|
19
|
+
<div class="item ${isActive ? 'active' : ''}" title=${ maybeTitle || '' }>
|
|
20
|
+
${showIcon ? html`<devtools-icon name="info"></devtools-icon>` : ''}
|
|
21
|
+
</div>
|
|
22
|
+
`
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Good:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
html`
|
|
29
|
+
<div class=${classMap({item: true, active: isActive})} title=${ifDefined(maybeTitle)}>
|
|
30
|
+
${showIcon ? html`<devtools-icon name="info"></devtools-icon>` : Lit.nothing}
|
|
31
|
+
</div>
|
|
32
|
+
`
|
|
33
|
+
```
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-localization-and-uistrings-hygiene
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Define user-facing strings in sentence-case UIStrings using complete sentences and i18nTemplate for embedded elements, and prune unused entries
|
|
8
|
+
- **Look for**: String concatenation around `i18nString(...)`, HTML/DOM elements interpolated without `i18nTemplate`, Title Case labels in `UIStrings`, unlocalized English literals in templates, or unused keys in `UIStrings`.
|
|
9
|
+
- **Do not flag**: Technical protocol identifiers, MIME types, or strings in `UIStringsNotTranslate` / `i18n.i18n.lockedString(...)`.
|
|
10
|
+
|
|
11
|
+
**Why.** Concatenating translated fragments breaks word order in non-English locales, title-Cased strings violate Chromium UX standards, translating English-only experimental strings wastes localization quota, and unused `UIStrings` entries bloat locale bundles.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const UIStrings = {
|
|
19
|
+
learnMoreAbout: 'Learn More About ', // Title case + fragmented sentence
|
|
20
|
+
unusedKey: 'Old label',
|
|
21
|
+
} as const;
|
|
22
|
+
html`${i18nString(UIStrings.learnMoreAbout)}<x-link href=${url}>CORS</x-link>`
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Good:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
const UIStrings = {
|
|
29
|
+
/**
|
|
30
|
+
* @description Link text explaining CORS errors.
|
|
31
|
+
* @example {CORS} PH1
|
|
32
|
+
*/
|
|
33
|
+
learnMoreAbout: 'Learn more about {PH1}',
|
|
34
|
+
} as const;
|
|
35
|
+
html`${i18nTemplate(UIStrings.learnMoreAbout, {PH1: html`<x-link href=${url}>CORS</x-link>`})}`
|
|
36
|
+
```
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-modern-component-and-encapsulation-standards
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Use modern DevTools UI primitives (`devtools-button`, `devtools-data-grid`, `devtools-icon`), #private fields, and module entrypoint imports
|
|
8
|
+
- **Look for**: `UI.Fragment.build`, legacy `DataGridImpl`, `extends LitElement`, `private ` keyword instead of `#` in new UI classes, or `<devtools-*>` tags in Lit templates without importing the corresponding component module entrypoint (e.g. `import * as Buttons from '../../ui/components/buttons/buttons.js'`).
|
|
9
|
+
- **Do not flag**: Overriding inherited `protected` lifecycle methods on framework base classes (e.g. extending `UI.Widget.Widget`).
|
|
10
|
+
|
|
11
|
+
**Why.** Legacy `UI.Fragment`, `DataGridImpl`, `LitElement`, `new Icon()`, and TypeScript `private` fields are superseded by standard `<devtools-*>` custom elements (imported via module entrypoints such as `import * as Buttons from '../../ui/components/buttons/buttons.js'` so custom tags register at runtime) and ECMAScript `#private` fields.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import type * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
19
|
+
export class MyView extends UI.Widget.VBox {
|
|
20
|
+
private grid = new DataGrid.DataGrid.DataGridImpl({...});
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Good:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
28
|
+
import * as DataGrid from '../../ui/legacy/components/data_grid/data_grid.js';
|
|
29
|
+
export class MyView extends UI.Widget.VBox {
|
|
30
|
+
#items: Item[] = [];
|
|
31
|
+
}
|
|
32
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-panel-and-meta-registration
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Follow DevTools panel directory conventions and register settings and views in the appropriate *-meta.ts scope
|
|
8
|
+
- **Look for**: Panel-level `UI.Widget` views placed inside `panels/<panel>/components/`, internal state flags registered with user-facing titles in `*-meta.ts`, or `loadView` callbacks calling `.instance()` instead of using the passed `Universe` context.
|
|
9
|
+
- **Do not flag**: Standalone reusable leaf components inside `components/` or genuine user-configurable preferences.
|
|
10
|
+
|
|
11
|
+
**Why.** Panel-level `UI.Widget` views belong directly under `front_end/panels/<panel>/` (reserving `components/` for reusable leaf components), internal non-user-facing settings must use `SettingCategory.NONE` or model descriptors rather than appearing in Settings UI, and shared SDK settings belong in `sdk-meta.ts`.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
Common.Settings.registerSettingExtension({
|
|
19
|
+
settingName: 'has-shown-internal-onboarding',
|
|
20
|
+
settingType: Common.Settings.SettingType.BOOLEAN,
|
|
21
|
+
defaultValue: false,
|
|
22
|
+
title: () => i18nString(UIStrings.onboardingShown),
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Good:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
Common.Settings.registerSettingExtension({
|
|
30
|
+
category: Common.Settings.SettingCategory.NONE,
|
|
31
|
+
settingName: 'has-shown-internal-onboarding',
|
|
32
|
+
settingType: Common.Settings.SettingType.BOOLEAN,
|
|
33
|
+
defaultValue: false,
|
|
34
|
+
});
|
|
35
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-performance-and-flamechart-rendering
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Precompute expensive metrics outside render loops, use Set/Map for O(1) lookups, and debounce high-frequency UI updates
|
|
8
|
+
- **Look for**: `.includes()` / `.find()` / `.sort()` inside canvas draw or event iteration loops, repeated `ResizeObserver` registrations on individual child items instead of the parent container, or un-debounced filter/mutation handlers.
|
|
9
|
+
- **Do not flag**: One-time initialization passes over bounded small arrays (less than 20 items).
|
|
10
|
+
|
|
11
|
+
**Why.** Performing linear `Array.includes`/`find` scans, sorting, or regex parsing inside FlameChart canvas draw loops, `ElementsTreeOutline` mutation callbacks, or Lit render passes causes frame drops and UI jank on large traces and DOM trees.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
for (const entry of traceEntries) {
|
|
19
|
+
if (allowedTypesArray.includes(entry.name) && Root.Runtime.experiments.isEnabled('exp')) {
|
|
20
|
+
drawEntry(entry);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Good:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
const isExpEnabled = Root.Runtime.experiments.isEnabled('exp');
|
|
29
|
+
for (const entry of traceEntries) {
|
|
30
|
+
if (isExpEnabled && ALLOWED_TYPES_SET.has(entry.name)) {
|
|
31
|
+
drawEntry(entry);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-pure-view-and-presenter-separation
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Keep UI.Widget view functions pure and stateless by computing presentation data in presenters and passing decoupled ViewInput data structures
|
|
8
|
+
- **Look for**: `DEFAULT_VIEW` or view helper functions calling `Common.Settings.Settings.instance()`, `SDK.*`, `Host.*`, mutating `input.*` arrays in place, or accepting raw `SDK`/`Protocol` domain objects instead of decoupled presentation interfaces on `ViewInput`.
|
|
9
|
+
- **Do not flag**: Legacy `UI.Widget` subclasses that have not yet migrated to a `DEFAULT_VIEW` function.
|
|
10
|
+
|
|
11
|
+
**Why.** In DevTools' MVP architecture, `DEFAULT_VIEW` functions must be pure projections of `ViewInput` to Lit templates. Querying SDK models, reading global settings, mutating presenter state, or calling host/clipboard APIs inside the view couples rendering to global state and breaks isolated view testing.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTMLElement): void => {
|
|
19
|
+
const showAdvanced = Common.Settings.Settings.instance().moduleSetting('show-advanced').get();
|
|
20
|
+
const sorted = input.items.sort((a, b) => a.name.localeCompare(b.name));
|
|
21
|
+
Lit.render(html`...`, target);
|
|
22
|
+
};
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Good:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
export const DEFAULT_VIEW = (input: ViewInput, _output: ViewOutput, target: HTMLElement): void => {
|
|
29
|
+
Lit.render(html`${input.sortedItems.map(item => html`<div>${item.name}</div>`)}`, target);
|
|
30
|
+
};
|
|
31
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-reactive-widget-update-lifecycle
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Schedule widget re-renders asynchronously via this.requestUpdate() and guard property setters with equality checks
|
|
8
|
+
- **Look for**: Widget property setters calling `this.performUpdate()` or `this.#view(...)` directly, or setters calling `this.requestUpdate()` without checking `if (this.#prop === value) return;`.
|
|
9
|
+
- **Do not flag**: Internal test helpers or synchronous initialization paths explicitly documented as requiring immediate flush.
|
|
10
|
+
|
|
11
|
+
**Why.** Calling `this.performUpdate()` or invoking `this.#view(...)` synchronously inside property setters causes redundant synchronous DOM renders when multiple properties change in the same tick. Setters should short-circuit if the value is unchanged and call `this.requestUpdate()`.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
set items(items: Item[]) {
|
|
19
|
+
this.#items = items;
|
|
20
|
+
this.performUpdate();
|
|
21
|
+
}
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Good:
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
set items(items: Item[]) {
|
|
28
|
+
if (this.#items === items) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
this.#items = items;
|
|
32
|
+
this.requestUpdate();
|
|
33
|
+
}
|
|
34
|
+
```
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-security-and-output-sanitization
|
|
3
|
+
rubric: security
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Sanitize untrusted strings, URLs, CSS selectors, and Markdown exports before rendering or exporting
|
|
8
|
+
- **Look for**: Raw string interpolation in `querySelector('[attr="' + val + '"]')` without `CSS.escape`, `href` attribute bindings with unvalidated `javascript:` URLs, Markdown table cell serialization without escaping `|*_<>\`, or raw HTML snippet generation without HTML escaping.
|
|
9
|
+
- **Do not flag**: Standard Lit `html` text bindings (`${text}`), which escape HTML entities automatically.
|
|
10
|
+
|
|
11
|
+
**Why.** Interpolating untrusted network URLs, DOM attributes, or user strings into raw HTML snippets, `CSS.escape`-free attribute selectors, Markdown table exports, or `href` attributes without protocol validation risks injection, XSS, broken layout formatting, or text spoofing.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const el = root.querySelector(`[data-key="${dynamicKey}"]`);
|
|
19
|
+
const markdownRow = `| ${cell.name} | ${cell.value} |`;
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
Good:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
const el = root.querySelector(`[data-key="${CSS.escape(dynamicKey)}"]`);
|
|
26
|
+
const escapeMd = (s: string) => s.replace(/[*_|<>]/g, '\\$&');
|
|
27
|
+
const markdownRow = `| ${escapeMd(cell.name)} | ${escapeMd(cell.value)} |`;
|
|
28
|
+
```
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-type-safety-and-exhaustiveness
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Model multi-state UI workflows with discriminated unions, Platform.assertNever exhaustiveness checks, and strict domain types
|
|
8
|
+
- **Look for**: `switch` statements over union/enum types missing `Platform.assertNever(x)` in `default:`, `any` or `declare` field modifiers in UI classes, or multiple boolean flags (`isLoading`, `isError`, `isEmpty`) representing mutually exclusive states.
|
|
9
|
+
- **Do not flag**: Switch statements that intentionally handle only a small subset of a large external protocol enum.
|
|
10
|
+
|
|
11
|
+
**Why.** Representing mutually exclusive UI states with loose optional boolean flags or `any` types permits impossible states and silently misses new enum variants. Discriminated unions paired with `Platform.assertNever` in `default:` branches enforce compile-time exhaustiveness.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
switch (state.type) {
|
|
19
|
+
case StateType.LOADING:
|
|
20
|
+
return renderLoading();
|
|
21
|
+
case StateType.LOADED:
|
|
22
|
+
return renderData(state.data);
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Good:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
switch (state.type) {
|
|
30
|
+
case StateType.LOADING:
|
|
31
|
+
return renderLoading();
|
|
32
|
+
case StateType.LOADED:
|
|
33
|
+
return renderData(state.data);
|
|
34
|
+
default:
|
|
35
|
+
Platform.assertNever(state, `Unhandled state: ${JSON.stringify(state)}`);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-view-output-and-callback-contracts
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Encapsulate imperative DOM actions in ViewOutput callbacks and pass user actions via semantic ViewInput callbacks instead of raw DOM references
|
|
8
|
+
- **Look for**: `ViewOutput` interfaces containing `HTMLElement` or `Element` properties, or `ViewInput` callbacks typed as `(event: Event) => void` instead of semantic domain values.
|
|
9
|
+
- **Do not flag**: Third-party editor or canvas host containers that require a raw mount `HTMLElement`.
|
|
10
|
+
|
|
11
|
+
**Why.** Exposing raw `HTMLElement` references on `ViewOutput` or passing raw `MouseEvent`/`KeyboardEvent` objects to presenter callbacks leaks DOM details into presenters. Views should populate narrow functional closures on `ViewOutput` (e.g. `output.focusInput = () => ...`) and unpack event values before calling `input.onSelect(value)`.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
export interface ViewOutput {
|
|
19
|
+
inputElement?: HTMLInputElement;
|
|
20
|
+
}
|
|
21
|
+
export interface ViewInput {
|
|
22
|
+
onInputChange: (event: Event) => void;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Good:
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
export interface ViewOutput {
|
|
30
|
+
focusInput?: () => void;
|
|
31
|
+
}
|
|
32
|
+
export interface ViewInput {
|
|
33
|
+
onFilterChanged: (newFilterText: string) => void;
|
|
34
|
+
}
|
|
35
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-visual-logging-instrumentation
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Instrument interactive UI elements and containers with kebab-case VisualLogging contexts registered in KnownContextValues
|
|
8
|
+
- **Look for**: Interactive elements (`<button>`, `<devtools-button>`, `<input>`, menus, drawers) missing `jslog` or `jslogContext`, non-kebab-case context names, or new context values missing from `KnownContextValues.ts`.
|
|
9
|
+
- **Do not flag**: Purely decorative icons or internal wrapper `<div>`s that represent neither a distinct visual section nor an interactive control.
|
|
10
|
+
|
|
11
|
+
**Why.** DevTools relies on Visual Elements (`jslog`) telemetry to measure feature usage. Omitting `jslog` on new buttons/toggles/menus, using localized or camelCase context strings, adding redundant panel prefixes inside already-logged containers, or dropping `jslog` during Lit refactors breaks analytics.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
html`<button @click=${input.onToggle}>${input.label}</button>`
|
|
19
|
+
// Or using localized string as context:
|
|
20
|
+
jslog=${VisualLogging.action(i18nString(UIStrings.clearAll)).track({click: true})}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Good:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
html`<devtools-button
|
|
27
|
+
.jslogContext=${'clear-all'}
|
|
28
|
+
@click=${input.onClear}>${i18nString(UIStrings.clearAll)}</devtools-button>`
|
|
29
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-weak-dom-references-and-observer-cleanup
|
|
3
|
+
rubric: design
|
|
4
|
+
severity: should_fix
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Store DOM node metadata in WeakMap or WeakRef collections and clean up observers when elements detach
|
|
8
|
+
- **Look for**: Strong `Map<Element, ...>` / `Set<Element>` collections holding DOM/model associations, `WeakMap` values retaining strong references back to their DOM keys, `ResizeObserver`/`IntersectionObserver` without `.unobserve()`/`.disconnect()` on teardown, or `ref(el => ...)` callbacks that do not handle `el === undefined`.
|
|
9
|
+
- **Do not flag**: Module-level `WeakMap<Element, ...>` globals whose values do not strongly reference the key, or short-lived local maps created and discarded within a single synchronous function call.
|
|
10
|
+
|
|
11
|
+
**Why.** Retaining DOM `Element` or `SDK.Target` references in strong `Map`/`Set` collections (or in `WeakMap` values that hold strong references back to their keys) prevents detached DOM trees from being garbage-collected, while leaving `ResizeObserver`, `MutationObserver`, or `Lit.Directives.ref` callbacks active after unmount leaks memory.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
const elementState = new Map<HTMLElement, State>();
|
|
19
|
+
// Or in Lit template:
|
|
20
|
+
html`<div ${ref(el => { this.#el = el as HTMLElement; })}></div>`
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Good:
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
readonly #elementState = new WeakMap<HTMLElement, State>();
|
|
27
|
+
// In Lit template, handle undefined when element detaches:
|
|
28
|
+
html`<div ${ref(el => { this.#el = el instanceof HTMLElement ? el : undefined; })}></div>`
|
|
29
|
+
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: devtools/ui-and-widgets/ui-widget-dom-and-listener-lifecycle
|
|
3
|
+
rubric: correctness
|
|
4
|
+
severity: blocking
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
**Rule.** Attach listeners to external models and managers in wasShown and detach them symmetrically in willHide
|
|
8
|
+
- **Look for**: `addEventListener`, `addModelListener`, or `addChangeListener` on singletons, models, or settings inside `UI.Widget` constructors or `wasShown()` without a matching `remove*` call in `willHide()` using the same function reference.
|
|
9
|
+
- **Do not flag**: Listeners attached to the widget's own internal DOM elements (`this.contentElement`), which are garbage-collected together with the widget.
|
|
10
|
+
|
|
11
|
+
**Why.** Subscribing to long-lived SDK `TargetManager`, `Settings`, or model events in a widget's constructor without unsubscribing in `willHide()` (or `onDetach()` / `onunbind()`) causes hidden panels to process background updates and leaks detached widget instances.
|
|
12
|
+
|
|
13
|
+
## Examples
|
|
14
|
+
|
|
15
|
+
Bad:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
constructor() {
|
|
19
|
+
super();
|
|
20
|
+
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
21
|
+
SDK.DOMModel.DOMModel, SDK.DOMModel.Events.DocumentUpdated, this.#onUpdate, this);
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Good:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
override wasShown(): void {
|
|
29
|
+
super.wasShown();
|
|
30
|
+
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
31
|
+
SDK.DOMModel.DOMModel, SDK.DOMModel.Events.DocumentUpdated, this.#onUpdate, this);
|
|
32
|
+
}
|
|
33
|
+
override willHide(): void {
|
|
34
|
+
super.willHide();
|
|
35
|
+
SDK.TargetManager.TargetManager.instance().removeModelListener(
|
|
36
|
+
SDK.DOMModel.DOMModel, SDK.DOMModel.Events.DocumentUpdated, this.#onUpdate, this);
|
|
37
|
+
}
|
|
38
|
+
```
|
|
@@ -34,14 +34,17 @@ Load the skill that matches what the diff touches, and apply its rules:
|
|
|
34
34
|
| :--- | :--- |
|
|
35
35
|
| Any `import` statement, or a new cross-module dependency | `devtools-imports` |
|
|
36
36
|
| `UI.Widget`, lit-html views, components, CSS | `ui-widgets` |
|
|
37
|
+
| Reviewing UI and widgets (`front_end/(panels|ui)/**/*.{ts,css}`) | `review-ui-widgets` |
|
|
37
38
|
| Migration of legacy imperative DOM to widgets or Lit | `ui-eng-vision-orchestrator` (and its sub-skills) |
|
|
38
39
|
| New or changed tests: choosing unit, API, or E2E | `devtools-testing-guidance` |
|
|
40
|
+
| Reviewing tests (`*.test.ts`, `test/**`, `front_end/testing/**`) | `review-tests` |
|
|
39
41
|
| Tests that use `describeWithEnvironment` or `describeWithMockConnection`, or foundation modules | `foundation-test-migration` |
|
|
40
42
|
| Ported Chromium web tests (`web_tests/http/tests/devtools`) | `migrate-chromium-test` |
|
|
41
43
|
| Flaky or disabled tests, or `it.skip` / `it.skipOnPlatforms` | `fix-tests` |
|
|
42
44
|
| `UIStrings` / user-facing text | `devtools-ux-writing-refactor` |
|
|
43
45
|
| Rendering user-controlled strings (URLs, names, console text) | `devtools-unicode-escaping` |
|
|
44
46
|
| `front_end/models/*`, `BUILD.gn`, `devtools_grd_files.gni`, entrypoints | `devtools-model-management` |
|
|
47
|
+
| Reviewing foundation, models, and build configs (`front_end/(core|models|entrypoints|generated)/**`, `BUILD.gn`, `*.gni`) | `review-models-core` |
|
|
45
48
|
| Merging modules or consolidating `BUILD.gn` | `merging-devtools-module` |
|
|
46
49
|
| `Settings` registrations and descriptors | `devtools-setting-migration` |
|
|
47
50
|
| Stack traces, source maps, `DebuggerWorkspaceBinding` | `devtools-source-maps` |
|
|
@@ -22,6 +22,7 @@ Use unit tests for isolated testing of individual functions, classes, models, he
|
|
|
22
22
|
- Use `TestUniverse` (and foundation test helpers) for easy, isolated setup of required dependencies and models.
|
|
23
23
|
- For testing UI widgets, use stubbed view functions and screenshot assertions rather than spinning up heavy DOM/browser infrastructure.
|
|
24
24
|
- **Location:** Co-located next to their implementation files (e.g. `TimelinePanel.ts` and `TimelinePanel.test.ts`).
|
|
25
|
+
- **Test functions:** import `describe`, `it`, `beforeEach`, etc. from `mocha` (e.g. `import {describe, it} from 'mocha';`). They are not available as globals.
|
|
25
26
|
- **BUILD.gn**: test file should be added to `devtools_ui_module("unittests")` or `devtools_foundation_module("foundation_unittests")` target in the corresponding `BUILD.gn` file.
|
|
26
27
|
|
|
27
28
|
---
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: review-models-core
|
|
3
|
+
description: >-
|
|
4
|
+
Reviews Chrome DevTools frontend changes in path group models-and-core (^front_end/(core|models|entrypoints|generated)/, BUILD\.gn$, \.gni$),
|
|
5
|
+
strictly reflecting review standards, architectural invariants, and security boundaries
|
|
6
|
+
derived from historical code reviews.
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Chrome DevTools frontend reviewer skill: models-and-core
|
|
10
|
+
|
|
11
|
+
This skill provides review guidance for Chrome DevTools frontend changes matching the `models-and-core` path group (^front_end/(core|models|entrypoints|generated)/, BUILD\.gn$, \.gni$). Every rule below recurred in at least 5 CLs from 2 distinct reviewers in historical reviews; cite the rule id in findings.
|
|
12
|
+
|
|
13
|
+
## Path group `models-and-core` (10 rules)
|
|
14
|
+
|
|
15
|
+
### `CORE_TRACE_ENGINE_HANDLER_INVARIANTS`: Normalize and precompute trace events in handler finalize passes using Types.Events.is* guards while keeping raw events immutable
|
|
16
|
+
- **Severity**: ERROR
|
|
17
|
+
- **Why**: Trace handlers (`front_end/models/trace/handlers/`) must normalize synthetic event fields, validate bounds, and group events once during `finalize()` so downstream insights and UI tracks do not repeatedly filter the raw trace array or mutate raw trace event objects.
|
|
18
|
+
- **Look for**: In-place property mutation of raw trace events, repeated full-trace `.filter()` scans inside insight calculators instead of handler precomputation, or ad-hoc property checks instead of `Types.Events.is*` (or `Trace.Types.Events.is*`) type guards.
|
|
19
|
+
- **Do not flag**: Constructing new synthetic trace event objects owned by the handler during `finalize()`.
|
|
20
|
+
|
|
21
|
+
### `CORE_SDK_MODEL_AND_TARGET_LIFECYCLE`: Manage SDK model and sub-target state on scoped manager instances using O(1) indexed maps rather than module globals or linear scans
|
|
22
|
+
- **Severity**: ERROR
|
|
23
|
+
- **Why**: Storing model tracking collections (`Set`/`Map`) at module scope leaks state across multiple `TestUniverse` instances and targets, while failing to track OOPIF/worker sub-targets or scanning DOM trees linearly for frame nodes causes bugs and $O(N)$ bottlenecks.
|
|
24
|
+
- **Look for**: Module-level `const tracked = new Map/Set()` in `core/sdk/` or `models/bindings/`, linear DOM tree traversals for frame/node lookups instead of indexed `Map`s, or target listeners that ignore sub-target attachment/detachment.
|
|
25
|
+
- **Do not flag**: Immutable module-level `Set` or `Map` lookup tables of constant string literals. Properties marked required (non-optional) in generated `front_end/generated/protocol.ts` CDP types (do not ask for redundant runtime null/undefined checks on them), or `node.shadowRoots()[0]` accesses (elements have at most one shadow root; the array return type is a legacy Shadow DOM v0 artifact).
|
|
26
|
+
|
|
27
|
+
### `CORE_GN_BUILD_AND_MODULE_LAYERING`: Enforce strict GN bundle visibility, declare complete deps/ts_deps, and never import UI or panel modules from foundation layers
|
|
28
|
+
- **Severity**: ERROR
|
|
29
|
+
- **Why**: DevTools enforces a strict DAG where `core/` and `models/` (`foundation`) must never depend on `ui/` or `panels/`. In `BUILD.gn`, modules must depend on `:bundle` targets across directories, register new files in `devtools_grd_files.gni` and `foundation_unittests`, and restrict panel `visibility`.
|
|
30
|
+
- **Look for**: Imports of `ui/` or `panels/` inside `core/` or `models/`, `visibility = [ "*" ]` on new panel `BUILD.gn` targets, direct internal file imports across module boundaries instead of `:bundle` namespace imports, or missing `foundation_unittests` entries.
|
|
31
|
+
- **Do not flag**: Core utility libraries intentionally exposed to the entire codebase with `visibility = [ "*" ]`.
|
|
32
|
+
|
|
33
|
+
### `CORE_AI_AGENT_CONTEXT_AND_PROMPT_DISCIPLINE`: Keep AI agent prompts, tool schemas, and data formatters deterministic, token-efficient, and decoupled from UI and locale state
|
|
34
|
+
- **Severity**: WARNING
|
|
35
|
+
- **Why**: AI agent data formatters (`models/ai_assistance/data_formatters/`) must produce deterministic, unlocalized, concise text representations decoupled from UI widgets and trace insight models, while tools must declare explicit permission policies and flatten verbose CDP types.
|
|
36
|
+
- **Look for**: Localized `i18nString` calls or verbose boilerplate prose inside AI data formatters, unsorted flag/property lists in prompt serializers, AI tools missing permission policy declarations, or monolithic trace models passed to response widgets.
|
|
37
|
+
- **Do not flag**: User-facing UI labels rendered in the AI assistance panel chrome rather than sent to the LLM.
|
|
38
|
+
|
|
39
|
+
### `CORE_RUNTIME_NEUTRALITY_AND_PLATFORM_UTILS`: Maintain runtime neutrality in foundation modules using Platform.HostRuntime, globalThis, and centralized core/platform utilities
|
|
40
|
+
- **Severity**: ERROR
|
|
41
|
+
- **Why**: Foundation modules (`core/` and `models/`) run in both browser DevTools and headless Node.js/worker environments (such as trace analysis and MCP servers). Accessing `window`, `navigator.userAgent`, or `document` directly breaks non-browser runtimes, and duplicating MIME/string/deferred utilities causes subtle bugs.
|
|
42
|
+
- **Look for**: `navigator.userAgent`, `window.setTimeout`, `window.atob`, manual `new Promise(r => { resolve = r; })` deferreds instead of `Promise.withResolvers()`, or ad-hoc MIME/escaping regexes in `core/` and `models/`.
|
|
43
|
+
- **Do not flag**: Browser-only UI components in `front_end/panels/` or `front_end/ui/`.
|
|
44
|
+
|
|
45
|
+
### `CORE_CDP_AND_EXTENSION_ERROR_HANDLING`: Handle CDP ProtocolResponseWithError and ContentDataOrError explicitly, release RemoteObject handles in finally blocks, and return Promises
|
|
46
|
+
- **Severity**: ERROR
|
|
47
|
+
- **Why**: CDP agent calls and `requestContentData()` resolve to error-bearing response objects (`getError()`, `ContentData.isError()`) rather than throwing, so wrapping them in `try/catch` is misleading. Furthermore, temporary `RemoteObject` handles must be released in `finally` blocks, and extension APIs must reject with sanitized `Error` instances.
|
|
48
|
+
- **Look for**: `try { await ...invoke_*() }` or `try { await request.requestContentData() }` blocks, `Runtime.evaluate` calls creating `RemoteObject`s without `release()` in `finally`, callback-taking SDK methods instead of `Promise`, or `reject(rawObject)` in `ExtensionAPI.ts`.
|
|
49
|
+
- **Do not flag**: `try/catch` blocks that wrap subsequent throwing operations like `JSON.parse()`. Properties marked required (non-optional) in generated `front_end/generated/protocol.ts` CDP types (do not ask for redundant runtime null/undefined checks on them), or `node.shadowRoots()[0]` accesses (elements have at most one shadow root; the array return type is a legacy Shadow DOM v0 artifact).
|
|
50
|
+
|
|
51
|
+
### `CORE_SECURITY_ORIGIN_AND_CAPABILITY_GUARDS`: Enforce security origin validation, enterprise policy guards, and branded UrlString types in the model and host layers
|
|
52
|
+
- **Severity**: ERROR
|
|
53
|
+
- **Why**: Security origin checks (SOP), workspace access boundaries, and enterprise/geo-restriction capability checks must be enforced in `core/` and `models/` using `SecurityOrigin`, `Common.ParsedURL`, and `Platform.DevToolsPath.UrlString` rather than relying on UI-layer checks or unvalidated source URLs.
|
|
54
|
+
- **Look for**: Unbranded `string` URLs in model/agent interfaces instead of `Platform.DevToolsPath.UrlString`, security origin checks performed only in UI views, or resource lookup errors returned before permission checks in `ExtensionServer`.
|
|
55
|
+
- **Do not flag**: Internal display-only label strings that are never used for resource resolution or security checks.
|
|
56
|
+
|
|
57
|
+
### `CORE_SOURCEMAP_AND_WORKSPACE_MAPPING`: Handle source map parsing, inline script offset translation, and scope tree resolution fault-tolerantly
|
|
58
|
+
- **Severity**: ERROR
|
|
59
|
+
- **Why**: Real-world source maps and inline `<script>` tags frequently contain malformed fields, UTF-8 characters, or non-zero line/column offsets. Source map consumers must translate raw inline script locations to relative locations, use UTF-8-safe URI encoding (`encodeURIComponent` with `try/catch` instead of `btoa`), and guard scope stack traversals.
|
|
60
|
+
- **Look for**: `window.btoa` on source map strings containing UTF-8, raw script locations passed to source map lookups without `rawLocationToRelativeLocation`, or unguarded `encodeURIComponent` / `JSON.parse` on external source map payloads.
|
|
61
|
+
- **Do not flag**: ASCII-only binary buffer encoding via `Common.Base64.encode`.
|
|
62
|
+
|
|
63
|
+
### `CORE_SETTINGS_AND_STORAGE_MIGRATION`: Guard settings and storage migrations with try/catch, preserve user preferences across renames, and clean up obsolete flags
|
|
64
|
+
- **Severity**: ERROR
|
|
65
|
+
- **Why**: Corrupted `localStorage` payloads or legacy setting schemas can throw during `JSON.parse` and break DevTools startup unless caught and reset. When migrating setting keys or storage formats, existing user selections must be migrated rather than overwritten.
|
|
66
|
+
- **Look for**: Unprotected `JSON.parse()` in `Settings.ts` or storage classes, setting key renames that discard previously stored user preferences, or experiment removals that leave orphaned `localStorage` keys behind.
|
|
67
|
+
- **Do not flag**: In-memory parsing of static constant JSON fixtures.
|
|
68
|
+
|
|
69
|
+
### `CORE_TRACE_INSIGHT_MODELS_AND_TIMING_TYPES`: Enforce branded timing types (Micro, Milli) in trace models and keep types.ts and insight models free of executable or presentation logic
|
|
70
|
+
- **Severity**: ERROR
|
|
71
|
+
- **Why**: Mixing microseconds and milliseconds causes 1000x calculation bugs across trace insights; branded types (`Types.Timing.Micro`, `Types.Timing.Milli`) and canonical conversion helpers (such as `Trace.Helpers.Timing.microToMilli` or `Platform.Timing.microSecondsToMilliSeconds`) prevent unit confusion. Placing executable functions in `types.ts` or UI/AI formatting in insight models violates trace architecture.
|
|
72
|
+
- **Look for**: Manual `/ 1000` or `* 1000` arithmetic on trace timestamps, executable functions placed in `models/trace/**/types.ts`, or CSS/DOM/AI markdown formatting inside `models/trace/insights/`.
|
|
73
|
+
- **Do not flag**: Type guard functions (`is*`) in `Trace.Types.Events` that only perform type predicate checks.
|