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
--[[
Exposes an interface to set global configuration values for Roact.
Configuration can only occur once, and should only be done by an application
using Roact, not a library.
Any keys that aren't recognized will cause errors. Configuration is only
intended for configuring Roact itself, not extensions or libraries.
Configuration is expected to be set immediately after loading Roact. Setting
configuration values after an application starts may produce unpredictable
behavior.
]]
-- Every valid configuration value should be non-nil in this table.
local defaultConfig = {
-- Enables asserts for internal Roact APIs. Useful for debugging Roact itself.
["internalTypeChecks"] = false,
-- Enables stricter type asserts for Roact's public API.
["typeChecks"] = false,
-- Enables storage of `debug.traceback()` values on elements for debugging.
["elementTracing"] = false,
-- Enables validation of component props in stateful components.
["propValidation"] = false,
}
-- Build a list of valid configuration values up for debug messages.
local defaultConfigKeys = {}
for key in pairs(defaultConfig) do
table.insert(defaultConfigKeys, key)
end
local Config = {}
function Config.new()
local self = {}
self._currentConfig = setmetatable({}, {
__index = function(_, key)
local message = ("Invalid global configuration key %q. Valid configuration keys are: %s"):format(
tostring(key),
table.concat(defaultConfigKeys, ", ")
)
error(message, 3)
end,
})
-- We manually bind these methods here so that the Config's methods can be
-- used without passing in self, since they eventually get exposed on the
-- root Roact object.
self.set = function(...)
return Config.set(self, ...)
end
self.get = function(...)
return Config.get(self, ...)
end
self.scoped = function(...)
return Config.scoped(self, ...)
end
self.set(defaultConfig)
return self
end
function Config:set(configValues)
-- Validate values without changing any configuration.
-- We only want to apply this configuration if it's valid!
for key, value in pairs(configValues) do
if defaultConfig[key] == nil then
local message = ("Invalid global configuration key %q (type %s). Valid configuration keys are: %s"):format(
tostring(key),
typeof(key),
table.concat(defaultConfigKeys, ", ")
)
error(message, 3)
end
-- Right now, all configuration values must be boolean.
if typeof(value) ~= "boolean" then
local message = (
"Invalid value %q (type %s) for global configuration key %q. Valid values are: true, false"
):format(tostring(value), typeof(value), tostring(key))
error(message, 3)
end
self._currentConfig[key] = value
end
end
function Config:get()
return self._currentConfig
end
function Config:scoped(configValues, callback)
local previousValues = {}
for key, value in pairs(self._currentConfig) do
previousValues[key] = value
end
self.set(configValues)
local success, result = pcall(callback)
self.set(previousValues)
assert(success, result)
end
return Config