From 19fb9879a9c7e8b8f331aaa4961efd25c6dc2fb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=B3=C3=B0i=20Karlsson?= Date: Sat, 22 Mar 2025 11:31:56 +0100 Subject: [PATCH 1/6] Implement `containerSeemsToBeEmptyDomElement` (regex free) --- internal/checker/checker.go | 17 +++++++++++- .../compiler/missingDomElements.errors.txt | 12 ++++----- .../missingDomElements.errors.txt.diff | 26 +++---------------- 3 files changed, 26 insertions(+), 29 deletions(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index c484837ca5..6839e59b79 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -10826,7 +10826,15 @@ func (c *Checker) isPropertyAccessible(node *ast.Node, isSuper bool, isWrite boo } func (c *Checker) containerSeemsToBeEmptyDomElement(containingType *Type) bool { - return false // !!! + if c.compilerOptions.Lib == nil || slices.Contains(c.compilerOptions.Lib, "dom") { + return false + } + return everyContainedType(containingType, func(t *Type) bool { + if t.symbol == nil { + return false + } + return t.symbol.Name == "EventTarget" || t.symbol.Name == "Node" || (strings.HasPrefix(t.symbol.Name, "HTML") && strings.HasSuffix(t.symbol.Name, "Element")) + }) && c.isEmptyObjectType(containingType) } func (c *Checker) checkAndReportErrorForExtendingInterface(errorLocation *ast.Node) bool { @@ -24531,6 +24539,13 @@ func everyType(t *Type, f func(*Type) bool) bool { return f(t) } +func everyContainedType(t *Type, f func(*Type) bool) bool { + if t.flags&TypeFlagsUnionOrIntersection != 0 { + return core.Every(t.Types(), f) + } + return f(t) +} + func (c *Checker) filterType(t *Type, f func(*Type) bool) *Type { if t.flags&TypeFlagsUnion != 0 { types := t.Types() diff --git a/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt b/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt index 4a39c99637..f1a351fec9 100644 --- a/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt +++ b/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt @@ -1,7 +1,7 @@ missingDomElements.ts(6,24): error TS2339: Property 'textContent' does not exist on type 'Element'. -missingDomElements.ts(7,28): error TS2339: Property 'textContent' does not exist on type 'HTMLElement'. -missingDomElements.ts(8,33): error TS2339: Property 'textContent' does not exist on type 'HTMLInputElement'. -missingDomElements.ts(9,47): error TS2339: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. +missingDomElements.ts(7,28): error TS2812: Property 'textContent' does not exist on type 'HTMLElement'. Try changing the 'lib' compiler option to include 'dom'. +missingDomElements.ts(8,33): error TS2812: Property 'textContent' does not exist on type 'HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. +missingDomElements.ts(9,47): error TS2812: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. missingDomElements.ts(16,32): error TS2339: Property 'textContent' does not exist on type 'HTMLElementFake'. missingDomElements.ts(17,21): error TS2339: Property 'textContent' does not exist on type 'Node'. @@ -17,13 +17,13 @@ missingDomElements.ts(17,21): error TS2339: Property 'textContent' does not exis !!! error TS2339: Property 'textContent' does not exist on type 'Element'. ({} as any as HTMLElement).textContent; ~~~~~~~~~~~ -!!! error TS2339: Property 'textContent' does not exist on type 'HTMLElement'. +!!! error TS2812: Property 'textContent' does not exist on type 'HTMLElement'. Try changing the 'lib' compiler option to include 'dom'. ({} as any as HTMLInputElement).textContent; ~~~~~~~~~~~ -!!! error TS2339: Property 'textContent' does not exist on type 'HTMLInputElement'. +!!! error TS2812: Property 'textContent' does not exist on type 'HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. ({} as any as EventTarget & HTMLInputElement).textContent ~~~~~~~~~~~ -!!! error TS2339: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. +!!! error TS2812: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. interface HTMLElementFake {} interface Node { diff --git a/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt.diff b/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt.diff index abd6c01518..6acd7b0efa 100644 --- a/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt.diff +++ b/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt.diff @@ -2,16 +2,10 @@ +++ new.missingDomElements.errors.txt @@= skipped -0, +0 lines =@@ -missingDomElements.ts(6,24): error TS2812: Property 'textContent' does not exist on type 'Element'. Try changing the 'lib' compiler option to include 'dom'. --missingDomElements.ts(7,28): error TS2812: Property 'textContent' does not exist on type 'HTMLElement'. Try changing the 'lib' compiler option to include 'dom'. --missingDomElements.ts(8,33): error TS2812: Property 'textContent' does not exist on type 'HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. --missingDomElements.ts(9,47): error TS2812: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. +missingDomElements.ts(6,24): error TS2339: Property 'textContent' does not exist on type 'Element'. -+missingDomElements.ts(7,28): error TS2339: Property 'textContent' does not exist on type 'HTMLElement'. -+missingDomElements.ts(8,33): error TS2339: Property 'textContent' does not exist on type 'HTMLInputElement'. -+missingDomElements.ts(9,47): error TS2339: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. - missingDomElements.ts(16,32): error TS2339: Property 'textContent' does not exist on type 'HTMLElementFake'. - missingDomElements.ts(17,21): error TS2339: Property 'textContent' does not exist on type 'Node'. - + missingDomElements.ts(7,28): error TS2812: Property 'textContent' does not exist on type 'HTMLElement'. Try changing the 'lib' compiler option to include 'dom'. + missingDomElements.ts(8,33): error TS2812: Property 'textContent' does not exist on type 'HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. + missingDomElements.ts(9,47): error TS2812: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. @@= skipped -13, +13 lines =@@ ({} as any as Element).textContent; @@ -20,16 +14,4 @@ +!!! error TS2339: Property 'textContent' does not exist on type 'Element'. ({} as any as HTMLElement).textContent; ~~~~~~~~~~~ --!!! error TS2812: Property 'textContent' does not exist on type 'HTMLElement'. Try changing the 'lib' compiler option to include 'dom'. -+!!! error TS2339: Property 'textContent' does not exist on type 'HTMLElement'. - ({} as any as HTMLInputElement).textContent; - ~~~~~~~~~~~ --!!! error TS2812: Property 'textContent' does not exist on type 'HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. -+!!! error TS2339: Property 'textContent' does not exist on type 'HTMLInputElement'. - ({} as any as EventTarget & HTMLInputElement).textContent - ~~~~~~~~~~~ --!!! error TS2812: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. -+!!! error TS2339: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. - - interface HTMLElementFake {} - interface Node { + !!! error TS2812: Property 'textContent' does not exist on type 'HTMLElement'. Try changing the 'lib' compiler option to include 'dom'. From 061e67073811dc2ab9ab74720c8bb9dc104ee043 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=B3=C3=B0i=20Karlsson?= Date: Sat, 22 Mar 2025 11:50:29 +0100 Subject: [PATCH 2/6] Add missing "Element" check --- internal/checker/checker.go | 2 +- .../compiler/missingDomElements.errors.txt | 4 ++-- .../compiler/missingDomElements.errors.txt.diff | 17 ----------------- 3 files changed, 3 insertions(+), 20 deletions(-) delete mode 100644 testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt.diff diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 6839e59b79..c9941ad87f 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -10833,7 +10833,7 @@ func (c *Checker) containerSeemsToBeEmptyDomElement(containingType *Type) bool { if t.symbol == nil { return false } - return t.symbol.Name == "EventTarget" || t.symbol.Name == "Node" || (strings.HasPrefix(t.symbol.Name, "HTML") && strings.HasSuffix(t.symbol.Name, "Element")) + return t.symbol.Name == "EventTarget" || t.symbol.Name == "Node" || t.symbol.Name == "Element" || (strings.HasPrefix(t.symbol.Name, "HTML") && strings.HasSuffix(t.symbol.Name, "Element")) }) && c.isEmptyObjectType(containingType) } diff --git a/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt b/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt index f1a351fec9..3663ff4a7d 100644 --- a/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt +++ b/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt @@ -1,4 +1,4 @@ -missingDomElements.ts(6,24): error TS2339: Property 'textContent' does not exist on type 'Element'. +missingDomElements.ts(6,24): error TS2812: Property 'textContent' does not exist on type 'Element'. Try changing the 'lib' compiler option to include 'dom'. missingDomElements.ts(7,28): error TS2812: Property 'textContent' does not exist on type 'HTMLElement'. Try changing the 'lib' compiler option to include 'dom'. missingDomElements.ts(8,33): error TS2812: Property 'textContent' does not exist on type 'HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. missingDomElements.ts(9,47): error TS2812: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. @@ -14,7 +14,7 @@ missingDomElements.ts(17,21): error TS2339: Property 'textContent' does not exis ({} as any as Element).textContent; ~~~~~~~~~~~ -!!! error TS2339: Property 'textContent' does not exist on type 'Element'. +!!! error TS2812: Property 'textContent' does not exist on type 'Element'. Try changing the 'lib' compiler option to include 'dom'. ({} as any as HTMLElement).textContent; ~~~~~~~~~~~ !!! error TS2812: Property 'textContent' does not exist on type 'HTMLElement'. Try changing the 'lib' compiler option to include 'dom'. diff --git a/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt.diff b/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt.diff deleted file mode 100644 index 6acd7b0efa..0000000000 --- a/testdata/baselines/reference/submodule/compiler/missingDomElements.errors.txt.diff +++ /dev/null @@ -1,17 +0,0 @@ ---- old.missingDomElements.errors.txt -+++ new.missingDomElements.errors.txt -@@= skipped -0, +0 lines =@@ --missingDomElements.ts(6,24): error TS2812: Property 'textContent' does not exist on type 'Element'. Try changing the 'lib' compiler option to include 'dom'. -+missingDomElements.ts(6,24): error TS2339: Property 'textContent' does not exist on type 'Element'. - missingDomElements.ts(7,28): error TS2812: Property 'textContent' does not exist on type 'HTMLElement'. Try changing the 'lib' compiler option to include 'dom'. - missingDomElements.ts(8,33): error TS2812: Property 'textContent' does not exist on type 'HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. - missingDomElements.ts(9,47): error TS2812: Property 'textContent' does not exist on type 'EventTarget & HTMLInputElement'. Try changing the 'lib' compiler option to include 'dom'. -@@= skipped -13, +13 lines =@@ - - ({} as any as Element).textContent; - ~~~~~~~~~~~ --!!! error TS2812: Property 'textContent' does not exist on type 'Element'. Try changing the 'lib' compiler option to include 'dom'. -+!!! error TS2339: Property 'textContent' does not exist on type 'Element'. - ({} as any as HTMLElement).textContent; - ~~~~~~~~~~~ - !!! error TS2812: Property 'textContent' does not exist on type 'HTMLElement'. Try changing the 'lib' compiler option to include 'dom'. From 3668686f09515f614f5635eea0547a9ad474d288 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=B3=C3=B0i=20Karlsson?= Date: Sat, 22 Mar 2025 15:40:18 +0100 Subject: [PATCH 3/6] Use correct dom lib name --- internal/checker/checker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index c9941ad87f..f0abae271f 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -10826,7 +10826,7 @@ func (c *Checker) isPropertyAccessible(node *ast.Node, isSuper bool, isWrite boo } func (c *Checker) containerSeemsToBeEmptyDomElement(containingType *Type) bool { - if c.compilerOptions.Lib == nil || slices.Contains(c.compilerOptions.Lib, "dom") { + if c.compilerOptions.Lib == nil || slices.Contains(c.compilerOptions.Lib, "lib.dom.d.ts") { return false } return everyContainedType(containingType, func(t *Type) bool { From d3fdd9cf64d08cada46d3c36d3848f5d3b90c4e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=B3=C3=B0i=20Karlsson?= Date: Sat, 22 Mar 2025 16:27:28 +0100 Subject: [PATCH 4/6] Revert dom change and add missing a-zA-Z check --- internal/checker/checker.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index f0abae271f..153bf14a60 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -10826,14 +10826,30 @@ func (c *Checker) isPropertyAccessible(node *ast.Node, isSuper bool, isWrite boo } func (c *Checker) containerSeemsToBeEmptyDomElement(containingType *Type) bool { - if c.compilerOptions.Lib == nil || slices.Contains(c.compilerOptions.Lib, "lib.dom.d.ts") { + if c.compilerOptions.Lib == nil || slices.Contains(c.compilerOptions.Lib, "dom") { return false } return everyContainedType(containingType, func(t *Type) bool { if t.symbol == nil { return false } - return t.symbol.Name == "EventTarget" || t.symbol.Name == "Node" || t.symbol.Name == "Element" || (strings.HasPrefix(t.symbol.Name, "HTML") && strings.HasSuffix(t.symbol.Name, "Element")) + if t.symbol.Name == "EventTarget" || t.symbol.Name == "Node" || t.symbol.Name == "Element" { + return true + } + + if !(strings.HasPrefix(t.symbol.Name, "HTML") && strings.HasSuffix(t.symbol.Name, "Element")) { + return false + } + + isMiddleAlpha := true + for _, r := range t.symbol.Name[4 : len(t.symbol.Name)-7] { + if !('a' <= r && r <= 'z') && !('A' <= r && r <= 'Z') { + isMiddleAlpha = false + break + } + } + + return isMiddleAlpha }) && c.isEmptyObjectType(containingType) } From 1a84d8d5705df98fd1e1f81d9d3115a7a203509d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=B3=C3=B0i=20Karlsson?= Date: Sat, 22 Mar 2025 22:07:32 +0100 Subject: [PATCH 5/6] Revert revert of lib.dom --- internal/checker/checker.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index 153bf14a60..fcc9d2e9d2 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -10826,7 +10826,7 @@ func (c *Checker) isPropertyAccessible(node *ast.Node, isSuper bool, isWrite boo } func (c *Checker) containerSeemsToBeEmptyDomElement(containingType *Type) bool { - if c.compilerOptions.Lib == nil || slices.Contains(c.compilerOptions.Lib, "dom") { + if c.compilerOptions.Lib == nil || slices.Contains(c.compilerOptions.Lib, "lib.dom.d.ts") { return false } return everyContainedType(containingType, func(t *Type) bool { From 8d19fa7f7431f910f621ace5d1347ba899db5736 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=B3=C3=B0i=20Karlsson?= Date: Sun, 23 Mar 2025 00:47:31 +0100 Subject: [PATCH 6/6] Clean up solution with CutPre/Suffix and isAsciiLetter --- internal/checker/checker.go | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/internal/checker/checker.go b/internal/checker/checker.go index fcc9d2e9d2..dbf81b50a0 100644 --- a/internal/checker/checker.go +++ b/internal/checker/checker.go @@ -10833,23 +10833,31 @@ func (c *Checker) containerSeemsToBeEmptyDomElement(containingType *Type) bool { if t.symbol == nil { return false } - if t.symbol.Name == "EventTarget" || t.symbol.Name == "Node" || t.symbol.Name == "Element" { + + name := t.symbol.Name + + switch name { + case "EventTarget", "Node", "Element": return true } - if !(strings.HasPrefix(t.symbol.Name, "HTML") && strings.HasSuffix(t.symbol.Name, "Element")) { + name, ok := strings.CutPrefix(name, "HTML") + if !ok { return false } - isMiddleAlpha := true - for _, r := range t.symbol.Name[4 : len(t.symbol.Name)-7] { - if !('a' <= r && r <= 'z') && !('A' <= r && r <= 'Z') { - isMiddleAlpha = false - break + name, ok = strings.CutSuffix(name, "Element") + if !ok { + return false + } + + for _, r := range name { + if !stringutil.IsASCIILetter(r) { + return false } } - return isMiddleAlpha + return true }) && c.isEmptyObjectType(containingType) }