-
Notifications
You must be signed in to change notification settings - Fork 58
/
Copy pathannotations.dart
485 lines (447 loc) · 17.9 KB
/
annotations.dart
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
// Copyright 2020 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Dummy annotations that would be used by Pub code generator
library over_react.component_declaration.annotations;
/// Annotation used with the `over_react` builder to declare a `UiFactory` for a component.
///
/// @Factory()
/// UiFactory<FooProps> Foo = _$Foo;
///
/// __NOTE:__ This is only required for legacy boilerplate and can be omitted
/// for new implementations. However, it can still be used for custom configurations.
///
/// If utilizing legacy boilerplate, must be accompanied by a [Props] and [Component2]
/// declaration.
class Factory {
const Factory();
}
/// Annotation used with the `over_react` builder to declare a `UiProps` mixin for a component.
///
/// Props are declared as fields, which act as stubs for generated getters/setters that proxy Map key-value pairs.
///
/// @Props()
/// mixin FooProps on UiProps {
/// String? bar;
/// }
///
/// __NOTE:__ This is only required for legacy boilerplate and can be omitted
/// for new implementations. However, it can still be used for custom configurations
/// (e.g. `keyNamespace`, `disableRequiredPropValidation`).
///
/// If utilizing legacy boilerplate, must be accompanied by a [Factory] and [Component2]
/// declaration.
class Props implements TypedMap {
/// A custom namespace for the keys of props defined in the annotated class,
/// overriding the default of `'${propsClassName}.'`.
@override
final String? keyNamespace;
/// Names of props to opt out of required prop validation for, both statically in the analyzer plugin
/// and at runtime when invoking the builder (only with asserts enabled).
///
/// Useful when you have a wrapper component that sets required prop manually.
///
/// For example:
///
/// ```dart
/// mixin FooProps on UiProps {
/// late String requiredPropAlwaysSetInWrapper;
/// late String requiredPropNotSetInWrapper;
/// }
///
/// UiFactory<FooProps> Foo = uiFunction((props) {
/// // ...
/// }, _$FooConfig);
///
/// @Props(disableRequiredPropValidation: {'requiredPropAlwaysSetInWrapper'})
/// class WrapperProps = UiProps with FooProps, WrapperPropsMixin;
///
/// UiFactory<WrapperProps> Wrapper = uiForwardRef((props, ref) {
/// return (Foo()
/// ..requiredPropAlwaysSetInWrapper = 'foo'
/// ..addProps(props.getPropsToForward(exclude: {WrapperPropsMixin}))
/// ..ref = ref
/// )();
/// }, _$WrapperConfig);
///```
final Set<String>? disableRequiredPropValidation;
/// Whether to disable validation for props defaulted in the class component associated
/// with these props (defaults to `true`).
///
/// This allows the declaration of non-nullable props with defaults that aren't considered
/// required by runtime validation or the analyzer plugin.
///
/// This only includes props defaulted directly in `defaultProps` or `getDefaultProps`,
/// and does not include any props added in other ways, such as super-calls or `addProps`/`addAll`.
///
/// For example, given the following component:
/// ```dart
/// UiFactory<FooProps> Foo = castUiFactory(_$Foo);
///
/// mixin FooProps on UiProps {
/// late bool defaultedProp;
/// late String requiredProp;
/// }
///
/// class FooComponent extends UiComponent2<FooProps> {
/// get defaultProps => (newProps()..defaultedProp = true);
///
/// render() {}
/// }
/// ```
///
/// The prop `defaultedProp` is not considered required because it has a default:
/// ```dart
/// Foo()(); // Has static and runtime errors about missing `requiredProp`
/// (Foo()..requiredProp = true)(); // Has no errors.
/// ```
final bool disableValidationForClassDefaultProps;
const Props({
this.keyNamespace,
this.disableRequiredPropValidation,
this.disableValidationForClassDefaultProps = true,
});
}
/// Annotation used with the `over_react` builder to declare a `UiState` mixin for a component.
///
/// State properties are declared as fields, which act as stubs for generated getters/setters that proxy Map key-value pairs.
///
/// @State()
/// mixin FooState on UiState {
/// bool baz;
/// }
///
/// __NOTE:__ This is only required for legacy boilerplate and can be omitted
/// for new implementations. However, it can still be used for custom configurations
/// (e.g. `keyNamespace`).
///
/// Optional. If utilizing legacy boilerplate, be accompanied by a [Factory],
/// [Props], and [Component2] declaration.
class State implements TypedMap {
/// A custom namespace for the keys of state properties defined in the annotated class,
/// overriding the default of `'${stateClassName}.'`.
@override
final String? keyNamespace;
const State({this.keyNamespace});
}
/// Annotation used with the `over_react` builder to declare a `UiComponent` class for a component.
///
/// @Component()
/// class FooComponent extends UiComponent<FooProps> {
/// render() => Dom.div()(props.bar);
/// }
///
/// Must be accompanied by a [Factory] and [Props] declaration.
///
/// __Deprecated.__ Use the [Component2] annotation alongside `UiComponent2` / `UiStatefulComponent2` instead.
@Deprecated('4.0.0')
class Component {
/// Whether the component clones or passes through its children and needs to be
/// treated as if it were the wrapped component when passed in to `isComponentOfType`.
final bool isWrapper;
/// The component class of this component's "parent type".
///
/// Used to enable inheritance in component type-checking in `isComponentOfType`.
///
/// E.g., if component `Bar` is a subtype of component `Foo`:
///
/// @Factory()
/// UiFactory<...> Foo = _$Foo;
/// ...
/// @Component()
/// class FooComponent ... {...}
///
/// @Factory()
/// UiFactory<...> Bar = _$Bar;
/// ...
/// @Component(subtypeOf: FooComponent)
/// class BarComponent ... {...}
///
/// then:
///
/// isComponentOfType(Bar()(), Bar); // true (due to normal type-checking)
/// isComponentOfType(Bar()(), Foo); // true (due to parent type-checking)
final Type? subtypeOf;
const Component({
this.isWrapper = false,
this.subtypeOf
});
}
/// Annotation used with the `over_react` builder to declare a `UiComponent2` class for a component.
///
/// @Component2()
/// class FooComponent extends UiComponent2<FooProps> {
/// render() => Dom.div()(props.bar);
/// }
///
/// __NOTE:__ This is only required for legacy boilerplate and can be omitted
/// for new implementations. However, it can still be used for custom configurations
/// (e.g. `subtypeOf`).
///
/// If utilizing legacy boilerplate, must be accompanied by a [Factory] and [Props]
/// declaration.
///
/// See also: `UiFactory.setTypeMeta` (via extension UiFactoryTypeMeta),
/// which can be used to provide configuration to function components,
/// which don't have this annotation.
class Component2 implements Component { // ignore: deprecated_member_use_from_same_package
/// Whether the component clones or passes through its children and needs to be
/// treated as if it were the wrapped component when passed in to `isComponentOfType`.
///
/// See also: `UiFactory.setTypeMeta` (via extension UiFactoryTypeMeta),
/// which can be used to provide configuration to function components,
/// which don't have this annotation.
@override
final bool isWrapper;
/// Whether the component serves as a React error boundary.
///
/// When set to `true`, this component will be able to make use of
/// the `componentDidCatch` and `getDerivedStateFromError` component lifecycle
/// methods in order to "catch" ReactJS errors from within its child component tree.
///
/// Check out the `ErrorBoundary` higher-order component for an example implementation.
///
/// > TODO (CPLAT-5037): Add an example of how to utilize the
/// `ErrorBoundaryMixin`, `ErrorBoundaryPropsMixin` and `ErrorBoundaryStateMixin` classes
/// in order to add default error boundary component behaviors to custom error boundaries.
///
/// > See: <https://reactjs.org/docs/error-boundaries.html>
final bool isErrorBoundary;
/// The component class of this component's "parent type".
///
/// See also: `UiFactory.setTypeMeta` (via extension UiFactoryTypeMeta),
/// which can be used to provide configuration to function components,
/// which don't have this annotation.
///
/// Used to enable inheritance in component type-checking in `isComponentOfType`.
///
/// E.g., if component `Bar` is a subtype of component `Foo`:
///
/// @Factory()
/// UiFactory<...> Foo = _$Foo;
/// ...
/// @Component2()
/// class FooComponent ... {...}
///
/// @Factory()
/// UiFactory<...> Bar = _$Bar;
/// ...
/// @Component2(subtypeOf: FooComponent)
/// class BarComponent ... {...}
///
/// then:
///
/// isComponentOfType(Bar()(), Bar); // true (due to normal type-checking)
/// isComponentOfType(Bar()(), Foo); // true (due to parent type-checking)
@override
final Type? subtypeOf;
const Component2({
this.isWrapper = false,
this.subtypeOf,
this.isErrorBoundary = false,
});
}
/// Annotation used with the `over_react` builder to declare an abstract `UiProps` mixin for an abstract component.
///
/// Props are declared as fields, which act as stubs for generated getters/setters that proxy Map key-value pairs.
///
/// @AbstractProps()
/// mixin QuxProps on UiProps {
/// int? quux;
/// }
///
/// __NOTE:__ This is only required for legacy boilerplate and can be omitted
/// for new implementations. However, it can still be used for custom configurations
/// (e.g. `keyNamespace`).
class AbstractProps implements TypedMap {
/// A custom namespace for the keys of props defined in the annotated class,
/// overriding the default of `'${propsClassName}.'`.
@override
final String? keyNamespace;
const AbstractProps({this.keyNamespace});
}
/// Annotation used with the `over_react` builder to declare an abstract `UiProps` class for an abstract component.
///
/// State properties are declared as fields, which act as stubs for generated getters/setters that proxy Map key-value pairs.
///
/// @AbstractState()
/// mixin QuxState on UiState {
/// String corge;
/// }
///
/// __NOTE:__ This is only required for legacy boilerplate and can be omitted
/// for new implementations. However, it can still be used for custom configurations.
class AbstractState implements TypedMap {
/// A custom namespace for the keys of state properties defined in the annotated class,
/// overriding the default of `'${stateClassName}.'`.
@override
final String? keyNamespace;
const AbstractState({this.keyNamespace});
}
/// Annotation used with the `over_react` builder to declare an abstract `UiComponent` class for an abstract component.
///
/// @AbstractComponent()
/// abstract class QuxComponent<TProps extends QuxProps> extends UiComponent<TProps> {}
///
/// __Deprecated.__ Use the [AbstractComponent2] annotation alongside `UiComponent2` / `UiStatefulComponent2` instead.
@Deprecated('4.0.0')
class AbstractComponent {
const AbstractComponent();
}
/// Annotation used with the `over_react` builder to declare an abstract `UiComponent2` class for an abstract component.
///
/// @AbstractComponent2()
/// abstract class FooComponent<TProps extends QuxProps> extends UiComponent2<TProps> {}
///
/// __NOTE:__ This is only required for legacy boilerplate and can be omitted
/// for new implementations. However, it can still be used for custom configurations
/// (e.g. `subtypeOf`).
class AbstractComponent2 implements AbstractComponent { // ignore: deprecated_member_use_from_same_package
const AbstractComponent2();
}
/// Annotation used with the `over_react` builder to declare a mixin for use in a `UiProps` class.
///
/// Props are declared as fields, which act as stubs for generated getters/setters that proxy Map key-value pairs.
///
/// @PropsMixin()
/// mixin GraultPropsMixin on UiProps {
/// Map get props;
///
/// Object? garply;
/// }
///
/// Classes using this annotation must include the abstract `props` getter.
///
/// __Deprecated.__ Use the `@Props()` annotation instead if you need to make use of an annotation argument.
/// Otherwise, this can be removed completely. Will be removed in the 4.0.0 release of over_react.
@Deprecated('Use the @Props() annotation if you need to make use of an annotation argument. Otherwise, this can be removed completely. Will be removed in the 4.0.0 release of over_react.')
class PropsMixin implements TypedMap {
/// A custom namespace for the keys of props defined in the annotated class,
/// overriding the default of `'${propsClassName}.'`.
@override
final String? keyNamespace;
const PropsMixin({this.keyNamespace});
}
/// Annotation used with the `over_react` builder to declare a mixin for use in a `UiState` class.
///
/// State properties are declared as fields, which act as stubs for generated getters/setters that proxy Map key-value pairs.
///
/// @StateMixin()
/// mixin WaldoStateMixin on UiState {
/// Map get state;
///
/// dynamic fred;
/// }
///
/// Classes using this annotation must include the abstract `state` getter.
///
/// __Deprecated.__ Use the `@State()` annotation instead if you need to make use of an annotation argument.
/// Otherwise, this can be removed completely. Will be removed in the 4.0.0 release of over_react.
@Deprecated('Use the @State() annotation if you need to make use of an annotation argument. Otherwise, this can be removed completely. Will be removed in the 4.0.0 release of over_react.')
class StateMixin implements TypedMap {
/// A custom namespace for the keys of state properties defined in the annotated class,
/// overriding the default of `'${stateClassName}.'`.
@override
final String? keyNamespace;
const StateMixin({this.keyNamespace});
}
/// Marks a `prop` as required to be set.
///
/// Prefer using `late` required props instead; this will eventually be deprecated.
///
/// Validation occurs in `UiComponent.validateRequiredProps` which requires super calls into `componentWillMount` and
/// `componentWillReceiveProps`.
///
/// mixin FooProps on UiProps {
/// @requiredProp
/// String requiredProp;
/// }
const Accessor requiredProp = Accessor(isRequired: true);
/// Marks a `prop` as required to be set, but allowed to be set explicitly to `null`.
///
/// Prefer using `late` required props instead; this will eventually be deprecated.
///
/// Validation occurs in `UiComponent.validateRequiredProps` which requires super calls into `componentWillMount` and
/// `componentWillReceiveProps`.
///
/// mixin FooProps on UiProps {
/// @nullableRequiredProp
/// String nullableRequiredProp;
/// }
const Accessor nullableRequiredProp = Accessor(isRequired: true, isNullable: true);
/// Annotation used with the `over_react` builder to customize individual accessors (props/state fields).
///
/// Validation (prefer using using `late` required props) occurs in `UiComponent.validateRequiredProps` which requires super calls into `componentWillMount` and
/// `componentWillReceiveProps`.
///
/// mixin FooProps on UiProps {
/// @Accessor(keyNamespace: '', key: 'custom_key')
/// String bar;
///
/// @Accessor(isRequired: true)
/// String requiredProp;
///
/// @Accessor(isRequired: true, isNullable: true)
/// String nullableRequiredProp;
/// }
///
/// Related: [requiredProp], [nullableRequiredProp].
class Accessor {
/// A key for the annotated accessor, overriding the default of the accessor's name.
final String? key;
/// A custom namespace for the key namespace of the annotated accessor,
/// overriding the default of `'${enclosingClassName}.'`.
final String? keyNamespace;
/// Whether the accessor is required to be set.
final bool isRequired;
/// Whether setting a prop to null is allowed.
final bool isNullable;
/// The error message displayed when the accessor is not set.
final String? requiredErrorMessage;
/// Whether to skip generating an accessor for this field.
final bool doNotGenerate;
const Accessor({
this.key,
this.keyNamespace,
this.isRequired = false,
this.isNullable = false,
this.requiredErrorMessage,
this.doNotGenerate = false,
});
}
abstract class TypedMap {
String? get keyNamespace;
}
/// Prevents required prop validation from being performed on a prop.
const _DisableRequiredPropValidation disableRequiredPropValidation = _DisableRequiredPropValidation();
class _DisableRequiredPropValidation {
const _DisableRequiredPropValidation();
}
/// Annotation that simplifies prop type conversion by generating [getter] and [setter] in
/// the respective getters and setters for the prop in the .over_react.g.dart part file.
///
/// A prop annotated with [ConvertProp] should always be typed the same as the [Converted] type.
class ConvertProp<Raw, Converted> {
final Converted Function(Raw) getter;
final Raw Function(Converted) setter;
const ConvertProp( this.setter, this.getter );
}
/// Utility version of [ConvertProp] for map props to generate getters and setters
/// to convert from `JsMap` to `Map` and back.
const _CommonConversionCases convertJsMapProp = _CommonConversionCases();
/// Utility version of [ConvertProp] for ref props to generate getters and setters
/// to convert from `JsRef` to `Ref` and back.
const _CommonConversionCases convertJsRefProp = _CommonConversionCases();
class _CommonConversionCases {
const _CommonConversionCases();
}