-
Notifications
You must be signed in to change notification settings - Fork 347
/
reflection.dart
100 lines (81 loc) · 3.22 KB
/
reflection.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
// Copyright 2021 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
import 'dart:js_util';
import 'package:js/js.dart';
import 'package:js/js_util.dart';
import 'utils.dart';
import 'utils.dart' as utils;
@JS("util.inspect.custom")
external Symbol get _inspectSymbol;
@JS("Object.getPrototypeOf")
external Object? _getPrototypeOf(Object object);
@JS("Object.setPrototypeOf")
external void _setPrototypeOf(Object object, Object prototype);
@JS("Object.create")
external Object _create(Object object);
/// The JavaScript constructor function that operates as a class.
///
/// We use this to perform reflection operations.
@JS()
@anonymous
class JSClass {
external Object get prototype;
external String get name;
}
/// Returns the reflected [JSClass] for a given object.
JSClass getJSClass(Object object) =>
getProperty(object, "constructor") as JSClass;
/// Creates a JS class with the given [name] and [constructor].
///
/// The [constructor] should take an initial `self` parameter, representing the
/// object being constructed.
JSClass createJSClass(String name, Function constructor) =>
allowInteropCaptureThisNamed(name, constructor) as JSClass;
/// Extension methods to make working reflectively with JS classes easier and
/// more readable.
extension JSClassExtension on JSClass {
/// Constructs an instance of this class.
Object construct(List<Object?> arguments) =>
callConstructor(this, arguments) as Object;
/// Sets a new name for this class.
void setName(String name) {
utils.defineGetter(this, 'name', value: name);
}
/// Returns this class's superclass.
JSClass get superclass =>
getProperty(_getPrototypeOf(prototype)!, 'constructor') as JSClass;
/// Injects [superclass] as this class's immediate superclass, otherwise
/// preserving the inheritance chain.
void injectSuperclass(JSClass superclass) {
_setPrototypeOf(superclass.prototype, this.superclass.prototype);
_setPrototypeOf(prototype, _create(superclass.prototype));
}
/// Sets the custom inspect logic for this class to [body].
void setCustomInspect(String inspect(Object self)) {
setProperty(prototype, _inspectSymbol,
allowInteropCaptureThis((Object self, _, __) => inspect(self)));
}
/// Defines a method with the given [name] and [body].
///
/// The [body] should take an initial `self` parameter, representing the
/// instance on which the method is being called.
void defineMethod(String name, Function body) {
setProperty(prototype, name, allowInteropCaptureThisNamed(name, body));
}
/// A shorthand for calling [defineMethod] multiple times.
void defineMethods(Map<String, Function> methods) {
methods.forEach(defineMethod);
}
/// Defines a getter with the given [name] and [body].
///
/// The [body] should take an initial `self` parameter, representing the
/// instance on which the method is being called.
void defineGetter(String name, Function body) {
utils.defineGetter(prototype, name, get: body);
}
/// A shorthand for calling [defineGetter] multiple times.
void defineGetters(Map<String, Function> getters) {
getters.forEach(defineGetter);
}
}