From 03ea9654e4674b703666bb544875d2e448286fce Mon Sep 17 00:00:00 2001 From: openclaw-bot Date: Sun, 24 May 2026 04:18:24 +0000 Subject: [PATCH 1/2] =?UTF-8?q?test(ci):=20RED=20=E2=80=94=20add=20eslint?= =?UTF-8?q?=20no-undef=20gate=20+=20canary=20undef=20var=20(#1342)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds the eslint frontend lint gate (.eslintrc.json + CI step in deploy.yml) PLUS a synthetic canary file (public/_lint_canary.js) that references an undefined variable. This commit is the RED commit per TDD discipline: - CI must FAIL on this commit (canary's undef var trips no-undef:error). - Verifies the gate is wired correctly and actually blocks merges. - The next commit removes the canary and CI goes GREEN. Config notes: - 257 globals declared in .eslintrc.json — discovered by walking public/*.js for window.X = ... assignments AND top-level function/const/let/var declarations. Cross-file globals are a real (pre-existing) reality of vanilla-JS-no-build CoreScope. - Minimal fix in public/map.js: typeof esc -> typeof globalThis.esc (esc is a local IIFE var in other files, not a true global). - eslint@8 (legacy config). Did NOT migrate to flat-config / eslint@9. Discovered via local lint run on master snapshot: - 0 latent undef-var bugs after globals were declared honestly (i.e., would-be #1318 candidates: none currently in tree). - 80 unused-var warnings (not blocking; argsIgnorePattern=^_ honored). Refs #1342 --- .eslintrc.json | 279 +++++++++++++++++++++++++++++++++++ .github/workflows/deploy.yml | 8 + public/_lint_canary.js | 5 + public/map.js | 6 +- 4 files changed, 296 insertions(+), 2 deletions(-) create mode 100644 .eslintrc.json create mode 100644 public/_lint_canary.js diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 00000000..f4bb0304 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,279 @@ +{ + "parserOptions": { + "ecmaVersion": 2022, + "sourceType": "script" + }, + "env": { + "browser": true, + "es2022": true + }, + "globals": { + "AreaFilter": "readonly", + "CACHE_INVALIDATE_MS": "readonly", + "CLIENT_CONFIG": "readonly", + "CLIENT_TTL": "readonly", + "ChannelColorPicker": "readonly", + "ChannelColors": "readonly", + "ChannelDecrypt": "readonly", + "ChannelQR": "readonly", + "Chart": "readonly", + "DIST_THRESHOLDS": "readonly", + "DragManager": "readonly", + "EXTERNAL_URLS": "readonly", + "FAV_KEY": "readonly", + "FilterUX": "readonly", + "GestureHints": "readonly", + "HEALTH_THRESHOLDS": "readonly", + "HashColor": "readonly", + "HopDisplay": "readonly", + "HopResolver": "readonly", + "IATA_CITIES": "readonly", + "IATA_COORDS_GEO": "readonly", + "L": "readonly", + "LIMITS": "readonly", + "Logo": "readonly", + "MAX_HOP_DIST": "readonly", + "MeshAudio": "readonly", + "MeshConfigReady": "readonly", + "PAYLOAD_COLORS": "readonly", + "PAYLOAD_TYPES": "readonly", + "PERF_SLOW_MS": "readonly", + "PROPAGATION_BUFFER_MS": "readonly", + "PULL_THRESHOLD_PX": "readonly", + "PacketFilter": "readonly", + "PathInspector": "readonly", + "QRCode": "readonly", + "ROLE_COLORS": "readonly", + "ROLE_EMOJI": "readonly", + "ROLE_LABELS": "readonly", + "ROLE_SHAPES": "readonly", + "ROLE_SORT": "readonly", + "ROLE_STYLE": "readonly", + "ROUTE_TYPES": "readonly", + "RegionFilter": "readonly", + "SITE_CONFIG": "readonly", + "SKEW_SEVERITY_COLORS": "readonly", + "SKEW_SEVERITY_LABELS": "readonly", + "SKEW_SEVERITY_ORDER": "readonly", + "SNR_THRESHOLDS": "readonly", + "SlideOver": "readonly", + "TILE_DARK": "readonly", + "TILE_LIGHT": "readonly", + "TYPE_COLORS": "readonly", + "TableResponsive": "readonly", + "TableSort": "readonly", + "TouchGestures": "readonly", + "TracesHelpers": "readonly", + "URLState": "readonly", + "WS_RECONNECT_MS": "readonly", + "_SITE_CONFIG_ORIGINAL_HOME": "readonly", + "__PERF_LOG_RENDER": "readonly", + "__bottomNavInitDone": "readonly", + "__corescopeLogo": "readonly", + "__dirname": "readonly", + "__filename": "readonly", + "__gestureHints1065Init": "readonly", + "__liveMQLBindCount": "readonly", + "__meshcoreMapInternals": "readonly", + "__navDrawer": "readonly", + "__navDrawerPointerBindCount": "readonly", + "__pathOverflowWired": "readonly", + "__scrollLock": "readonly", + "__touchGestures1062InitCount": "readonly", + "_analyticsChannelTbodyHtml": "readonly", + "_analyticsChannelTheadHtml": "readonly", + "_analyticsDecorateChannels": "readonly", + "_analyticsHashStatCardsHtml": "readonly", + "_analyticsLoadChannelSort": "readonly", + "_analyticsRenderCollisionsFromServer": "readonly", + "_analyticsRenderMultiByteAdopters": "readonly", + "_analyticsRenderMultiByteCapability": "readonly", + "_analyticsRfNFColumnChart": "readonly", + "_analyticsSaveChannelSort": "readonly", + "_analyticsSortChannels": "readonly", + "_apiCache": "readonly", + "_apiPerf": "readonly", + "_channelsBeginMessageRequestForTest": "readonly", + "_channelsGetStateForTest": "readonly", + "_channelsHandleWSBatchForTest": "readonly", + "_channelsIsStaleMessageRequestForTest": "readonly", + "_channelsLoadChannelsForTest": "readonly", + "_channelsProcessWSBatchForTest": "readonly", + "_channelsReconcileSelectionForTest": "readonly", + "_channelsRefreshMessagesForTest": "readonly", + "_channelsSelectChannelForTest": "readonly", + "_channelsSetObserverRegionsForTest": "readonly", + "_channelsSetStateForTest": "readonly", + "_channelsShouldProcessWSMessageForRegion": "readonly", + "_customizerV2": "readonly", + "_ensurePullIndicator": "readonly", + "_inflight": "readonly", + "_isTouchDevice": "readonly", + "_liveAddFeedItem": "readonly", + "_liveBufferPacket": "readonly", + "_liveBuildClickablePathPopupHtml": "readonly", + "_liveBuildObserverIataMap": "readonly", + "_liveClickablePaths": "readonly", + "_liveDbPacketToLive": "readonly", + "_liveExpandToBufferEntries": "readonly", + "_liveExpandToBufferEntriesAsync": "readonly", + "_liveFormatLiveTimestampHtml": "readonly", + "_liveGetFavoritePubkeys": "readonly", + "_liveGetNodeFilterKeys": "readonly", + "_liveGetObserverIataMap": "readonly", + "_liveIsNodeFavorited": "readonly", + "_liveNodeActivity": "readonly", + "_liveNodeData": "readonly", + "_liveNodeMarkers": "readonly", + "_livePacketInvolvesFavorite": "readonly", + "_livePacketInvolvesFilterNode": "readonly", + "_livePacketMatchesRegion": "readonly", + "_livePruneClickablePaths": "readonly", + "_livePruneStaleNodes": "readonly", + "_liveRebuildFeedList": "readonly", + "_liveResolveHopPositions": "readonly", + "_liveSEG_MAP": "readonly", + "_liveSetMarkerColor": "readonly", + "_liveSetMarkerSize": "readonly", + "_liveSetNodeFilter": "readonly", + "_liveSetObserverIataMap": "readonly", + "_liveSpeedLabel": "readonly", + "_liveVCR": "readonly", + "_liveVcrPause": "readonly", + "_liveVcrResumeLive": "readonly", + "_liveVcrSetMode": "readonly", + "_liveVcrSpeedCycle": "readonly", + "_live_packetTimestamp": "readonly", + "_mapGetNeighborPubkeys": "readonly", + "_mapSelectRefNode": "readonly", + "_meshAudioVoices": "readonly", + "_meshcoreHeatLayer": "readonly", + "_meshcoreLiveHeatLayer": "readonly", + "_nodesGetAllNodes": "readonly", + "_nodesGetSortState": "readonly", + "_nodesGetStatusInfo": "readonly", + "_nodesGetStatusTooltip": "readonly", + "_nodesIsAdvertMessage": "readonly", + "_nodesMatchesSearch": "readonly", + "_nodesRenderNodeTimestampHtml": "readonly", + "_nodesRenderNodeTimestampText": "readonly", + "_nodesSetAllNodes": "readonly", + "_nodesSetSortState": "readonly", + "_nodesSortArrow": "readonly", + "_nodesSortNodes": "readonly", + "_nodesSyncClaimedToFavorites": "readonly", + "_nodesToggleSort": "readonly", + "_packetsTestAPI": "readonly", + "_panelCorner": "readonly", + "_pendingPathInspectorRoute": "readonly", + "_perfWriteSourcesPrev": "readonly", + "_pullIndicator": "readonly", + "_pullToast": "readonly", + "_pullToastTimer": "readonly", + "_reducedMotionMQL": "readonly", + "_showPullToast": "readonly", + "_themeRefreshTimer": "readonly", + "_vcrFormatTime": "readonly", + "addEventListener": "readonly", + "api": "readonly", + "apiPerf": "readonly", + "bindFavStars": "readonly", + "buildHexLegend": "readonly", + "buildNodesQuery": "readonly", + "buildPacketsQuery": "readonly", + "clearParsedCache": "readonly", + "closeMoreMenu": "readonly", + "closeNav": "readonly", + "comparePacketSets": "readonly", + "computeBreakdownRanges": "readonly", + "computeOverlapStats": "readonly", + "connectWS": "readonly", + "copyToClipboard": "readonly", + "createColoredHexDump": "readonly", + "currentPage": "readonly", + "currentSkewValue": "readonly", + "debounce": "readonly", + "debouncedOnWS": "readonly", + "destroy": "readonly", + "devicePixelRatio": "readonly", + "dispatchEvent": "readonly", + "drawPacketRoute": "readonly", + "escapeHtml": "readonly", + "exports": "readonly", + "favStar": "readonly", + "filterPacketsByRoute": "readonly", + "formatAbsoluteTimestamp": "readonly", + "formatChartAxisLabel": "readonly", + "formatDistance": "readonly", + "formatDistanceRound": "readonly", + "formatDrift": "readonly", + "formatEngineBadge": "readonly", + "formatHex": "readonly", + "formatIsoLike": "readonly", + "formatSkew": "readonly", + "formatTimestamp": "readonly", + "formatTimestampCustom": "readonly", + "formatTimestampWithTooltip": "readonly", + "formatVersionBadge": "readonly", + "getDistanceUnit": "readonly", + "getFavorites": "readonly", + "getHashParams": "readonly", + "getHealthThresholds": "readonly", + "getNodeStatus": "readonly", + "getParsedDecoded": "readonly", + "getParsedPath": "readonly", + "getPathLenOffset": "readonly", + "getResolvedPath": "readonly", + "getTileUrl": "readonly", + "getTimestampCustomFormat": "readonly", + "getTimestampFormatPreset": "readonly", + "getTimestampMode": "readonly", + "getTimestampTimezone": "readonly", + "global": "readonly", + "initGeoFilterOverlay": "readonly", + "initTabBar": "readonly", + "invalidateApiCache": "readonly", + "isFavorite": "readonly", + "isTransportRoute": "readonly", + "makeColumnsResizable": "readonly", + "makeRoleMarkerSVG": "readonly", + "miniMarkdown": "readonly", + "module": "readonly", + "navigate": "readonly", + "observerSkewSeverity": "readonly", + "offWS": "readonly", + "onWS": "readonly", + "pad2": "readonly", + "pad3": "readonly", + "pages": "readonly", + "payloadTypeColor": "readonly", + "payloadTypeName": "readonly", + "process": "readonly", + "pullReconnect": "readonly", + "qrcode": "readonly", + "registerPage": "readonly", + "renderSkewBadge": "readonly", + "renderSkewSparkline": "readonly", + "require": "readonly", + "routeLayer": "readonly", + "routeTypeName": "readonly", + "setupPullToReconnect": "readonly", + "syncBadgeColors": "readonly", + "timeAgo": "readonly", + "toggleFavorite": "readonly", + "transportBadge": "readonly", + "truncate": "readonly", + "ws": "readonly", + "wsListeners": "readonly" + }, + "rules": { + "no-undef": "error", + "no-unused-vars": [ + "warn", + { + "argsIgnorePattern": "^_", + "varsIgnorePattern": "^_" + } + ] + } +} \ No newline at end of file diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index d7050edf..0e016dcf 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -107,6 +107,14 @@ jobs: node test-area-filter.js node test-issue-1293-marker-shapes.js + - name: 🧹 Frontend lint (eslint no-undef) — issue #1342 + run: | + set -e + # Use eslint@8 (legacy .eslintrc.json). Don't migrate to flat-config / eslint@9. + # --no-save: avoid touching package.json / no committed node_modules. + npm install --no-save --no-audit --no-fund eslint@8 + npx eslint public/*.js + - name: Verify proto syntax run: | set -e diff --git a/public/_lint_canary.js b/public/_lint_canary.js new file mode 100644 index 00000000..16f0c6eb --- /dev/null +++ b/public/_lint_canary.js @@ -0,0 +1,5 @@ +/* Canary file for TDD red commit on issue #1342. + * Asserts the eslint no-undef gate actually fails on an undefined variable. + * Removed in the green commit. */ +'use strict'; +undefinedCanaryVar.shouldFailLint(); diff --git a/public/map.js b/public/map.js index 54fb9504..301489f7 100644 --- a/public/map.js +++ b/public/map.js @@ -20,8 +20,10 @@ let userHasMoved = false; let controlsCollapsed = false; - // Safe escape — falls back to identity if app.js hasn't loaded yet - const safeEsc = (typeof esc === 'function') ? esc : function (s) { return s; }; + // Safe escape — falls back to identity if app.js hasn't loaded yet. + // Note: `esc` is not a true global; some IIFEs define it locally. Reference + // through globalThis so the optional lookup is safe under `no-undef`. + const safeEsc = (typeof globalThis.esc === 'function') ? globalThis.esc : function (s) { return s; }; // Roles loaded from shared roles.js (ROLE_STYLE, ROLE_LABELS, ROLE_COLORS globals) From b514aeb74e4afd245e2cd540882e82a4263b7fc7 Mon Sep 17 00:00:00 2001 From: openclaw-bot Date: Sun, 24 May 2026 04:18:43 +0000 Subject: [PATCH 2/2] =?UTF-8?q?feat(ci):=20GREEN=20=E2=80=94=20remove=20li?= =?UTF-8?q?nt=20canary,=20eslint=20passes=20(#1342)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes public/_lint_canary.js. With the canary gone, `npx eslint public/*.js` exits 0 against the current tree (0 errors, 80 unused-var warnings — not blocking). Mutation check: re-adding the canary re-trips the gate (verified locally). This is the green commit that completes the red→green TDD cycle for #1342. Fixes #1342 --- public/_lint_canary.js | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 public/_lint_canary.js diff --git a/public/_lint_canary.js b/public/_lint_canary.js deleted file mode 100644 index 16f0c6eb..00000000 --- a/public/_lint_canary.js +++ /dev/null @@ -1,5 +0,0 @@ -/* Canary file for TDD red commit on issue #1342. - * Asserts the eslint no-undef gate actually fails on an undefined variable. - * Removed in the green commit. */ -'use strict'; -undefinedCanaryVar.shouldFailLint();