1- use llrt_utils:: primordials:: { BasePrimordials , Primordial } ;
21// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
32// SPDX-License-Identifier: Apache-2.0
4- use rquickjs:: { atom:: PredefinedAtom , function:: Opt , Class , Ctx , Object , Result } ;
3+ use llrt_utils:: {
4+ option:: Undefined ,
5+ primordials:: { BasePrimordials , Primordial } ,
6+ } ;
7+ use rquickjs:: {
8+ atom:: PredefinedAtom ,
9+ class:: JsClass ,
10+ function:: { Constructor , Opt } ,
11+ object:: Property ,
12+ prelude:: This ,
13+ Class , Coerced , Ctx , Exception , IntoJs , Object , Result , Value ,
14+ } ;
515
6- #[ rquickjs:: class]
716#[ derive( rquickjs:: class:: Trace , rquickjs:: JsLifetime ) ]
817pub struct DOMException {
9- message : String ,
1018 name : String ,
19+ message : String ,
1120 stack : String ,
1221 code : u8 ,
1322}
1423
24+ fn add_constants ( obj : & Object < ' _ > ) -> Result < ( ) > {
25+ const CONSTANTS : [ ( & str , u8 ) ; 25 ] = [
26+ ( "INDEX_SIZE_ERR" , 1 ) ,
27+ ( "DOMSTRING_SIZE_ERR" , 2 ) ,
28+ ( "HIERARCHY_REQUEST_ERR" , 3 ) ,
29+ ( "WRONG_DOCUMENT_ERR" , 4 ) ,
30+ ( "INVALID_CHARACTER_ERR" , 5 ) ,
31+ ( "NO_DATA_ALLOWED_ERR" , 6 ) ,
32+ ( "NO_MODIFICATION_ALLOWED_ERR" , 7 ) ,
33+ ( "NOT_FOUND_ERR" , 8 ) ,
34+ ( "NOT_SUPPORTED_ERR" , 9 ) ,
35+ ( "INUSE_ATTRIBUTE_ERR" , 10 ) ,
36+ ( "INVALID_STATE_ERR" , 11 ) ,
37+ ( "SYNTAX_ERR" , 12 ) ,
38+ ( "INVALID_MODIFICATION_ERR" , 13 ) ,
39+ ( "NAMESPACE_ERR" , 14 ) ,
40+ ( "INVALID_ACCESS_ERR" , 15 ) ,
41+ ( "VALIDATION_ERR" , 16 ) ,
42+ ( "TYPE_MISMATCH_ERR" , 17 ) ,
43+ ( "SECURITY_ERR" , 18 ) ,
44+ ( "NETWORK_ERR" , 19 ) ,
45+ ( "ABORT_ERR" , 20 ) ,
46+ ( "URL_MISMATCH_ERR" , 21 ) ,
47+ ( "QUOTA_EXCEEDED_ERR" , 22 ) ,
48+ ( "TIMEOUT_ERR" , 23 ) ,
49+ ( "INVALID_NODE_TYPE_ERR" , 24 ) ,
50+ ( "DATA_CLONE_ERR" , 25 ) ,
51+ ] ;
52+
53+ for ( key, value) in CONSTANTS {
54+ obj. prop ( key, Property :: from ( value) . enumerable ( ) ) ?;
55+ }
56+
57+ Ok ( ( ) )
58+ }
59+
60+ impl < ' js > JsClass < ' js > for DOMException {
61+ const NAME : & ' static str = "DOMException" ;
62+ type Mutable = rquickjs:: class:: Writable ;
63+ fn prototype ( ctx : & Ctx < ' js > ) -> rquickjs:: Result < Option < Object < ' js > > > {
64+ use rquickjs:: class:: impl_:: { MethodImpl , MethodImplementor } ;
65+ let proto = Object :: new ( ctx. clone ( ) ) ?;
66+ let implementor = MethodImpl :: < Self > :: new ( ) ;
67+ implementor. implement ( & proto) ?;
68+ add_constants ( & proto) ?;
69+
70+ Ok ( Some ( proto) )
71+ }
72+ fn constructor ( ctx : & Ctx < ' js > ) -> Result < Option < Constructor < ' js > > > {
73+ use rquickjs:: class:: impl_:: { ConstructorCreate , ConstructorCreator } ;
74+ let implementor = ConstructorCreate :: < Self > :: new ( ) ;
75+ let constructor = implementor
76+ . create_constructor ( ctx) ?
77+ . expect ( "DOMException must have a constructor" ) ;
78+ add_constants ( & constructor) ?;
79+
80+ Ok ( Some ( constructor) )
81+ }
82+ }
83+
84+ impl < ' js > IntoJs < ' js > for DOMException {
85+ fn into_js ( self , ctx : & rquickjs:: Ctx < ' js > ) -> Result < Value < ' js > > {
86+ let cls = Class :: < Self > :: instance ( ctx. clone ( ) , self ) ?;
87+ rquickjs:: IntoJs :: into_js ( cls, ctx)
88+ }
89+ }
90+
91+ impl < ' js > rquickjs:: FromJs < ' js > for DOMException
92+ where
93+ for < ' a > rquickjs:: class:: impl_:: CloneWrapper < ' a , Self > :
94+ rquickjs:: class:: impl_:: CloneTrait < Self > ,
95+ {
96+ fn from_js ( ctx : & Ctx < ' js > , value : Value < ' js > ) -> Result < Self > {
97+ use rquickjs:: class:: impl_:: { CloneTrait , CloneWrapper } ;
98+ let value = Class :: < Self > :: from_js ( ctx, value) ?;
99+ let borrow = value. try_borrow ( ) ?;
100+ Ok ( CloneWrapper ( & * borrow) . wrap_clone ( ) )
101+ }
102+ }
103+
15104#[ rquickjs:: methods]
16105impl DOMException {
17106 #[ qjs( constructor) ]
18- pub fn new ( ctx : Ctx < ' _ > , message : Opt < String > , name : Opt < String > ) -> Result < Self > {
19- let primordials = BasePrimordials :: get ( & ctx) ?;
107+ pub fn new (
108+ ctx : Ctx < ' _ > ,
109+ this : This < Value < ' _ > > ,
110+ message : Opt < Undefined < Coerced < String > > > ,
111+ name : Opt < Undefined < Coerced < String > > > ,
112+ ) -> Result < Self > {
113+ if this. 0 . is_undefined ( ) {
114+ return Err ( Exception :: throw_type (
115+ & ctx,
116+ "Cannot call the DOMException constructor without 'new'" ,
117+ ) ) ;
118+ }
119+
120+ let message = match message. 0 {
121+ Some ( Undefined ( Some ( message) ) ) => message. 0 ,
122+ _ => String :: new ( ) ,
123+ } ;
124+
125+ let name = match name. 0 {
126+ Some ( Undefined ( Some ( message) ) ) => DOMExceptionName :: from ( message. 0 ) ,
127+ _ => DOMExceptionName :: Error ,
128+ } ;
129+
130+ Self :: new_with_name ( & ctx, name, message)
131+ }
132+
133+ #[ qjs( skip) ]
134+ pub fn new_with_name ( ctx : & Ctx < ' _ > , name : DOMExceptionName , message : String ) -> Result < Self > {
135+ let primordials = BasePrimordials :: get ( ctx) ?;
20136
21137 let new: Object = primordials
22138 . constructor_error
23139 . construct ( ( message. clone ( ) , ) ) ?;
24140
25- let message = message. 0 . unwrap_or ( String :: from ( "" ) ) ;
26- let name = name. 0 . unwrap_or ( String :: from ( "Error" ) ) ;
27-
28- // https://webidl.spec.whatwg.org/#dfn-error-names-table
29- let code = match name. as_str ( ) {
30- "IndexSizeError" => 1 ,
31- "HierarchyRequestError" => 3 ,
32- "WrongDocumentError" => 4 ,
33- "InvalidCharacterError" => 5 ,
34- "NoModificationAllowedError" => 7 ,
35- "NotFoundError" => 8 ,
36- "NotSupportedError" => 9 ,
37- "InUseAttributeError" => 10 ,
38- "InvalidStateError" => 11 ,
39- "SyntaxError" => 12 ,
40- "InvalidModificationError" => 13 ,
41- "NamespaceError" => 14 ,
42- "InvalidAccessError" => 15 ,
43- "TypeMismatchError" => 17 ,
44- "SecurityError" => 18 ,
45- "NetworkError" => 19 ,
46- "AbortError" => 20 ,
47- "URLMismatchError" => 21 ,
48- "QuotaExceededError" => 22 ,
49- "TimeoutError" => 23 ,
50- "InvalidNodeTypeError" => 24 ,
51- "DataCloneError" => 25 ,
52- _ => 0 ,
53- } ;
54-
55141 Ok ( Self {
142+ name : name. as_str ( ) . to_string ( ) ,
143+ code : name. code ( ) ,
56144 message,
57- name,
58- code,
59145 stack : new. get :: < _ , String > ( PredefinedAtom :: Stack ) ?,
60146 } )
61147 }
62148
63- #[ qjs( get) ]
64- fn message ( & self ) -> String {
65- self . message . clone ( )
149+ #[ qjs( get, enumerable , configurable ) ]
150+ fn message ( & self ) -> & str {
151+ self . message . as_str ( )
66152 }
67153
68- #[ qjs( get) ]
69- pub fn name ( & self ) -> String {
70- self . name . clone ( )
154+ #[ qjs( get, enumerable , configurable ) ]
155+ pub fn name ( & self ) -> & str {
156+ self . name . as_str ( )
71157 }
72158
73- #[ qjs( get) ]
159+ #[ qjs( get, enumerable , configurable ) ]
74160 pub fn code ( & self ) -> u8 {
75161 self . code
76162 }
@@ -80,20 +166,124 @@ impl DOMException {
80166 self . stack . clone ( )
81167 }
82168
83- #[ allow( clippy:: inherent_to_string) ]
84- #[ qjs( rename = PredefinedAtom :: ToString ) ]
85- pub fn to_string ( & self ) -> String {
86- if self . message . is_empty ( ) {
87- return self . name . clone ( ) ;
169+ #[ qjs( get, rename = PredefinedAtom :: SymbolToStringTag ) ]
170+ pub fn to_string_tag ( & self ) -> & str {
171+ "DOMException"
172+ }
173+ }
174+
175+ macro_rules! create_dom_exception {
176+ ( $name: ident, $( $variant: ident) ,+ $( , ) ?) => {
177+ #[ derive( Debug ) ]
178+ pub enum $name {
179+ $(
180+ $variant,
181+ ) +
182+ Other ( String ) ,
183+ }
184+
185+ impl $name {
186+ pub fn as_str( & self ) -> & str {
187+ match self {
188+ $(
189+ Self :: $variant => stringify!( $variant) ,
190+ ) +
191+ Self :: Other ( value) => value,
192+ }
193+ }
88194 }
89195
90- [ self . name . as_str ( ) , self . message . as_str ( ) ] . join ( ": " )
196+ impl From <String > for $name {
197+ fn from( value: String ) -> Self {
198+ match value. as_str( ) {
199+ $(
200+ stringify!( $variant) => Self :: $variant,
201+ ) +
202+ _ => Self :: Other ( value) ,
203+ }
204+ }
205+ }
206+ } ;
207+ }
208+
209+ // https://webidl.spec.whatwg.org/#dfn-error-names-table
210+ create_dom_exception ! (
211+ DOMExceptionName ,
212+ IndexSizeError ,
213+ HierarchyRequestError ,
214+ WrongDocumentError ,
215+ InvalidCharacterError ,
216+ NoModificationAllowedError ,
217+ NotFoundError ,
218+ NotSupportedError ,
219+ InUseAttributeError ,
220+ InvalidStateError ,
221+ SyntaxError ,
222+ InvalidModificationError ,
223+ NamespaceError ,
224+ InvalidAccessError ,
225+ TypeMismatchError ,
226+ SecurityError ,
227+ NetworkError ,
228+ AbortError ,
229+ URLMismatchError ,
230+ QuotaExceededError ,
231+ TimeoutError ,
232+ InvalidNodeTypeError ,
233+ DataCloneError ,
234+ EncodingError ,
235+ NotReadableError ,
236+ UnknownError ,
237+ ConstraintError ,
238+ DataError ,
239+ TransactionInactiveError ,
240+ ReadOnlyError ,
241+ VersionError ,
242+ OperationError ,
243+ NotAllowedError ,
244+ Error ,
245+ ) ;
246+
247+ impl DOMExceptionName {
248+ fn code ( & self ) -> u8 {
249+ match self {
250+ DOMExceptionName :: IndexSizeError => 1 ,
251+ DOMExceptionName :: HierarchyRequestError => 3 ,
252+ DOMExceptionName :: WrongDocumentError => 4 ,
253+ DOMExceptionName :: InvalidCharacterError => 5 ,
254+ DOMExceptionName :: NoModificationAllowedError => 7 ,
255+ DOMExceptionName :: NotFoundError => 8 ,
256+ DOMExceptionName :: NotSupportedError => 9 ,
257+ DOMExceptionName :: InUseAttributeError => 10 ,
258+ DOMExceptionName :: InvalidStateError => 11 ,
259+ DOMExceptionName :: SyntaxError => 12 ,
260+ DOMExceptionName :: InvalidModificationError => 13 ,
261+ DOMExceptionName :: NamespaceError => 14 ,
262+ DOMExceptionName :: InvalidAccessError => 15 ,
263+ DOMExceptionName :: TypeMismatchError => 17 ,
264+ DOMExceptionName :: SecurityError => 18 ,
265+ DOMExceptionName :: NetworkError => 19 ,
266+ DOMExceptionName :: AbortError => 20 ,
267+ DOMExceptionName :: URLMismatchError => 21 ,
268+ DOMExceptionName :: QuotaExceededError => 22 ,
269+ DOMExceptionName :: TimeoutError => 23 ,
270+ DOMExceptionName :: InvalidNodeTypeError => 24 ,
271+ DOMExceptionName :: DataCloneError => 25 ,
272+ _ => 0 ,
273+ }
91274 }
92275}
93276
94277pub fn init ( ctx : & Ctx < ' _ > ) -> Result < ( ) > {
95278 let globals = ctx. globals ( ) ;
96- Class :: < DOMException > :: define ( & globals) ?;
279+
280+ if let Some ( constructor) = Class :: < DOMException > :: create_constructor ( ctx) ? {
281+ // the wpt tests expect this particular property descriptor
282+ globals. prop (
283+ DOMException :: NAME ,
284+ Property :: from ( constructor) . writable ( ) . configurable ( ) ,
285+ ) ?;
286+ }
97287
98288 let dom_ex_proto = Class :: < DOMException > :: prototype ( ctx) ?. unwrap ( ) ;
99289 let error_prototype = & BasePrimordials :: get ( ctx) ?. prototype_error ;
0 commit comments