Skip to content

Commit 7b469f0

Browse files
committed
Miscellaneous updates
- Improve sanitization of variable values. - Update toList() parsing to not remove null values.
1 parent d782977 commit 7b469f0

File tree

4 files changed

+79
-57
lines changed

4 files changed

+79
-57
lines changed

lib/src/api/models/color_rgba.dart

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,15 @@ class ColorRGBA with EquatableMixin, SerializableMixin {
111111
);
112112
}
113113

114+
/// Converts this [ColorRGBA] to [ColorRGB] by removing the alpha channel.
115+
String toHex() {
116+
final r = (this.r * 255).toInt().toRadixString(16).padLeft(2, '0');
117+
final g = (this.g * 255).toInt().toRadixString(16).padLeft(2, '0');
118+
final b = (this.b * 255).toInt().toRadixString(16).padLeft(2, '0');
119+
final a = (this.a * 255).toInt().toRadixString(16).padLeft(2, '0');
120+
return '#$a$r$g$b'.toUpperCase();
121+
}
122+
114123
@override
115124
Map toJson() => _$ColorRGBAToJson(this);
116125

lib/src/api/models/variables_model.dart

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import 'dart:convert';
2+
13
import 'package:equatable/equatable.dart';
24
import 'package:json_annotation/json_annotation.dart';
35

@@ -76,7 +78,7 @@ class VariableData
7678
VariableData copyWith({
7779
String? id,
7880
String? name,
79-
String? value,
81+
Object? value,
8082
VariableType? type,
8183
bool? isUsed,
8284
Set<String>? nodes,
@@ -128,24 +130,43 @@ class VariableData
128130
}
129131

130132
/// Returns the value converted to the appropriate type according to [type].
131-
String? sanitizeValueForVariableType(String? value, VariableType type) {
133+
/// Supported color values:
134+
/// - ColorRGBA
135+
/// - ColorRGB
136+
/// - Hex color string
137+
/// - Flutter Color object
138+
String? sanitizeValueForVariableType(Object? value, VariableType type) {
132139
if (value == null) return null;
133-
if (value.isEmpty) return '';
134-
return switch (type) {
135-
VariableType.text => value,
136-
VariableType.integer => num.tryParse(value).toInt()?.toString(),
137-
VariableType.decimal => num.tryParse(value).toDouble()?.toString(),
138-
VariableType.boolean =>
139-
bool.tryParse(value, caseSensitive: false)?.toString(),
140-
VariableType.color =>
141-
RegExp(r'^#[0-9a-fA-F]{2,8}$', caseSensitive: false).hasMatch(value)
142-
? value.toUpperCase()
143-
: null,
144-
// TODO: this could be a bit expensive. Maybe enable only when required!
145-
// VariableType.map => tryJsonDecode(value),
146-
// VariableType.list => value.toList(),
147-
_ => value,
148-
};
140+
// if (value.isEmpty) return '';
141+
switch (type) {
142+
case VariableType.text:
143+
return value.toString();
144+
case VariableType.integer:
145+
return num.tryParse(value.toString()).toInt()?.toString();
146+
case VariableType.decimal:
147+
return num.tryParse(value.toString()).toDouble()?.toString();
148+
case VariableType.boolean:
149+
return bool.tryParse(value.toString(), caseSensitive: false)?.toString();
150+
case VariableType.color:
151+
if (value is ColorRGBA) return value.toHex();
152+
if (value is ColorRGB) return value.toColorRGBA()!.toHex();
153+
final colorMatch = flutterColorRegex.firstMatch(value.toString());
154+
if (colorMatch != null) {
155+
return ColorRGBA.fromHex(colorMatch.namedGroup('hex')!)?.toHex();
156+
}
157+
final hexMatch = hexColorRegex.firstMatch(value.toString());
158+
if (hexMatch != null) return value.toString().toUpperCase();
159+
return null;
160+
// This could be a bit expensive. Maybe enable only when required!
161+
case VariableType.map:
162+
if (value is Map) return jsonEncode(value);
163+
final map = value.toMap();
164+
return map != null ? jsonEncode(map) : null;
165+
case VariableType.list:
166+
if (value is List) return jsonEncode(value);
167+
final list = value.toList();
168+
return list != null ? jsonEncode(list) : null;
169+
}
149170
}
150171

151172
/// Contains all the variables associated with a canvas inside a page.
@@ -242,20 +263,24 @@ class CanvasVariableData extends VariableData {
242263
@override
243264
CanvasVariableData copyWith({
244265
String? name,
245-
String? value,
266+
Object? value,
246267
VariableType? type,
247268
String? id,
248269
bool? isUsed,
249270
String? canvasId,
250271
Set<String>? nodes,
251-
}) =>
252-
CanvasVariableData(
253-
name: name ?? this.name,
254-
value: value ?? this.value,
255-
type: type ?? this.type,
256-
id: id ?? this.id,
257-
canvasId: canvasId ?? this.canvasId,
258-
);
272+
}) {
273+
final String? sanitizedValue = value == null
274+
? null
275+
: sanitizeValueForVariableType(value, type ?? this.type);
276+
return CanvasVariableData(
277+
name: name ?? this.name,
278+
value: sanitizedValue ?? this.value,
279+
type: type ?? this.type,
280+
id: id ?? this.id,
281+
canvasId: canvasId ?? this.canvasId,
282+
);
283+
}
259284

260285
@override
261286
List<Object?> get props => [...super.props, canvasId];

lib/src/api/regexes.dart

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,15 @@ const String rawVariableNamePattern = r'[A-Za-z]+[A-Za-z0-9_]*';
196196

197197
/// Regex for [rawVariableNamePattern].
198198
final RegExp rawVariableNameRegex = RegExp(rawVariableNamePattern);
199+
200+
/// A regex that matches a string representation of a color from Flutter SDK.
201+
const String flutterColorPattern = r'^Color\(0x(?<hex>[A-Fa-f0-9]{8})\)$';
202+
203+
/// Regex for [flutterColorPattern].
204+
final RegExp flutterColorRegex = RegExp(flutterColorPattern);
205+
206+
/// A regex that matches a hex color string.
207+
const String hexColorPattern = r'^#[A-Fa-f0-9]{2,8}$';
208+
209+
/// Regex for [hexColorPattern].
210+
final RegExp hexColorRegex = RegExp(hexColorPattern);

lib/src/api/typed_value.dart

Lines changed: 6 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -210,58 +210,34 @@ extension ConversionExt on Object? {
210210
return list.map<int?>((e) => e?.toInt()).toList().tryCast<R>();
211211
}
212212
if (R == List<int>) {
213-
return list
214-
.map<int?>((e) => e?.toInt())
215-
.whereNotNull()
216-
.toList()
217-
.tryCast<R>();
213+
return list.map<int?>((e) => e?.toInt()).toList().tryCast<R>();
218214
}
219215
if (R == List<double>) {
220-
return list
221-
.map<double?>((e) => e.toDouble())
222-
.whereNotNull()
223-
.toList()
224-
.tryCast<R>();
216+
return list.map<double?>((e) => e.toDouble()).toList().tryCast<R>();
225217
}
226218
if (R == List<double?>) {
227219
return list.map<double?>((e) => e.toDouble()).toList().tryCast<R>();
228220
}
229221
if (R == List<num>) {
230-
return list
231-
.map<num?>((e) => e.toNum())
232-
.whereNotNull()
233-
.toList()
234-
.tryCast<R>();
222+
return list.map<num?>((e) => e.toNum()).toList().tryCast<R>();
235223
}
236224
if (R == List<num?>) {
237225
return list.map<num?>((e) => e.toNum()).toList().tryCast<R>();
238226
}
239227
if (R == List<bool>) {
240-
return list
241-
.map<bool?>((e) => e.toBool())
242-
.whereNotNull()
243-
.toList()
244-
.tryCast<R>();
228+
return list.map<bool?>((e) => e.toBool()).toList().tryCast<R>();
245229
}
246230
if (R == List<bool?>) {
247231
return list.map<bool?>((e) => e.toBool()).toList().tryCast<R>();
248232
}
249233
if (R == List<String>) {
250-
return list
251-
.map<String?>((e) => e.toString())
252-
.whereNotNull()
253-
.toList()
254-
.tryCast<R>();
234+
return list.map<String?>((e) => e.toString()).toList().tryCast<R>();
255235
}
256236
if (R == List<String?>) {
257237
return list.map<String?>((e) => e.toString()).toList().tryCast<R>();
258238
}
259239
if (R == List<Map>) {
260-
return list
261-
.map<Map?>((e) => e.toMap())
262-
.whereNotNull()
263-
.toList()
264-
.tryCast<R>();
240+
return list.map<Map?>((e) => e.toMap()).toList().tryCast<R>();
265241
}
266242
if (R == List<Map?>) {
267243
return list.map<Map?>((e) => e.toMap()).toList().tryCast<R>();

0 commit comments

Comments
 (0)