Skip to content

Commit 523f169

Browse files
committed
fix: Add work around to be able to always be able to regenerate when run. Add documentation around the usage of useNextGen, add tests
1 parent 12c138a commit 523f169

File tree

6 files changed

+233
-197
lines changed

6 files changed

+233
-197
lines changed

openapi-generator-annotations/lib/src/openapi_generator_annotations_base.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,16 @@ class Openapi {
9696

9797
/// Use the next generation of the generator.
9898
///
99+
/// This annotation informs the generator to use the new generator pathway.
100+
/// Enabling this option allows for incremental changes to the [inputSpecFile]
101+
/// to be generated even though the annotation was unchanged.
102+
///
103+
/// Due to some limitations with build_runner and it only running when the
104+
/// asset graph has changed, a generated line get injected at the beginning of
105+
/// the file at the end of each run.
106+
///
107+
/// This will become the default behaviour in the next Major version (v5).
108+
///
99109
/// Default: false
100110
final bool useNextGen;
101111

openapi-generator/lib/src/gen_on_spec_changes.dart

Lines changed: 15 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,11 @@ FutureOr<Map<String, dynamic>> loadSpec(
8787
}
8888

8989
return Future.error(
90-
OutputMessage(message: 'Unable to find spec file $specPath'));
90+
OutputMessage(
91+
message: 'Unable to find spec file $specPath',
92+
level: Level.WARNING,
93+
stackTrace: StackTrace.current),
94+
);
9195
}
9296

9397
/// Verify if the [loadedSpec] has a diff compared to the [cachedSpec].
@@ -97,101 +101,7 @@ bool isSpecDirty({
97101
required Map<String, dynamic> cachedSpec,
98102
required Map<String, dynamic> loadedSpec,
99103
}) {
100-
// The spec always needs to be updated if the cached spec is empty, unless
101-
// the loaded spec is also empty.
102-
if (cachedSpec.isEmpty) {
103-
return true && loadedSpec.isNotEmpty;
104-
}
105-
// TODO: Should this be a future? This way the errors can be bubbled up?
106-
if (loadedSpec.keys.length == cachedSpec.keys.length) {
107-
for (final entry in cachedSpec.entries) {
108-
if (!loadedSpec.containsKey(entry.key)) {
109-
// The original key was removed / renamed in the new map.
110-
// This will likely occur within the paths map.
111-
return true;
112-
}
113-
final lEntry = loadedSpec[entry.key];
114-
// Naive assumption that each of the values are the same
115-
// TODO: Stop assuming the values are of the same type.
116-
if (entry.value is Map) {
117-
final v = entry.value as Map<String, dynamic>;
118-
final l = lEntry as Map<String, dynamic>;
119-
return isSpecDirty(cachedSpec: v, loadedSpec: l);
120-
} else if (entry.value is List) {
121-
// Cast both entries to a list of entries
122-
var v = entry.value as List;
123-
var l = lEntry as List;
124-
125-
if (v.length != l.length) {
126-
return true;
127-
}
128-
129-
try {
130-
// Cast the list into it's typed variants
131-
if (v.every((element) => element is num)) {
132-
if (v.every((element) => element is int)) {
133-
v = v.cast<int>();
134-
l = l.cast<int>();
135-
} else if (v.every((element) => element is double)) {
136-
v = v.cast<double>();
137-
l = l.cast<double>();
138-
}
139-
} else if (v.every((element) => element is String)) {
140-
v = v.cast<String>();
141-
l = l.cast<String>();
142-
} else if (v.every((element) => element is bool)) {
143-
v = v.cast<bool>();
144-
l = l.cast<bool>();
145-
}
146-
} on TypeError catch (e, st) {
147-
log('Failed to cast entry, this may be due to an API change',
148-
stackTrace: st, error: e);
149-
// If there is an error casting this is likely due to the type of L not
150-
// matching which could indicate that the type of the loaded spec may
151-
// have changed.
152-
return true;
153-
}
154-
155-
// Loop through each of the entries, this now means ordering matters.
156-
// TODO: Verify if this is desired behaviour.
157-
for (var i = 0; i < v.length; i++) {
158-
if (v[i] != l[i]) {
159-
return true;
160-
}
161-
}
162-
163-
return false;
164-
} else {
165-
try {
166-
// The value is a scalar value
167-
var v = entry.value;
168-
var l = lEntry;
169-
170-
if (v is num) {
171-
if (v is int) {
172-
return v != (l as int);
173-
} else {
174-
return v != (l as double);
175-
}
176-
} else if (v is bool) {
177-
return v != (l as bool);
178-
} else if (v is String) {
179-
return v != (l as String);
180-
} else {
181-
// Enums are represented as lists
182-
return false;
183-
}
184-
} catch (e, st) {
185-
// TODO: This is likely a poor assumption to make
186-
log('Failed to parse value, likely do to type change',
187-
stackTrace: st, error: e);
188-
return true;
189-
}
190-
}
191-
}
192-
return false;
193-
}
194-
return true;
104+
return jsonEncode(cachedSpec) != jsonEncode(loadedSpec);
195105
}
196106

197107
/// Convert the [YamlMap] to a Dart [Map].
@@ -260,15 +170,14 @@ Future<void> cacheSpec({
260170
log('No previous openapi-generated cache found. Creating cache');
261171
}
262172

263-
return await outputFile.writeAsString(jsonEncode(spec)).then(
264-
(_) => log('Successfully wrote cache.'),
265-
onError: (e, st) {
266-
log(
267-
'Failed to write cache',
268-
error: e,
269-
stackTrace: st,
173+
return await outputFile.writeAsString(jsonEncode(spec), flush: true).then(
174+
(_) => log('Successfully wrote cache.'),
175+
onError: (e, st) => Future.error(
176+
OutputMessage(
177+
message: 'Failed to write cache',
178+
additionalContext: e,
179+
stackTrace: st,
180+
),
181+
),
270182
);
271-
return Future.error('Failed to write cache');
272-
},
273-
);
274183
}

0 commit comments

Comments
 (0)