Skip to content

Commit 0b2f932

Browse files
committed
Merge branch 'modelType-refactor' into modelType-refactor+type-alias-referencing
2 parents 3c7fd2d + 14510b1 commit 0b2f932

15 files changed

+134
-91
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ dartdoc:
289289
command: ["bin/drill.dart"]
290290
setup_command: ["bin/setup.dart"]
291291
description: "Puts holes in things."
292+
compile_args: ["--no-sound-null-safety"]
292293
echo:
293294
macos: ['/bin/sh', '-c', 'echo']
294295
setup_macos: ['/bin/sh', '-c', 'setup.sh']
@@ -328,6 +329,9 @@ The `description` is just a short description of the tool for use as help text.
328329
Only tools which are configured in the `dartdoc_options.yaml` file are able to
329330
be invoked.
330331

332+
The `compile_args` tag is used to pass options to the dart compiler when the
333+
first run of the tool is being snapshotted.
334+
331335
To use the tools in comment documentation, use the `{@tool <name> [<options>
332336
...] [$INPUT]}` directive to invoke the tool:
333337

analysis_options.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ analyzer:
1818
linter:
1919
rules:
2020
- always_declare_return_types
21+
- avoid_dynamic_calls
2122
- avoid_single_cascade_in_expression_statements
2223
- avoid_unused_constructor_parameters
2324
- annotate_overrides

analysis_options_presubmit.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ analyzer:
2121
linter:
2222
rules:
2323
- always_declare_return_types
24+
- avoid_dynamic_calls
2425
- avoid_single_cascade_in_expression_statements
2526
- avoid_unused_constructor_parameters
2627
- annotate_overrides

lib/src/dartdoc_options.dart

Lines changed: 72 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ const int _kIntVal = 0;
3939
const double _kDoubleVal = 0.0;
4040
const bool _kBoolVal = true;
4141

42+
const String _kCompileArgsTagName = 'compile_args';
43+
4244
int get _usageLineLength => stdout.hasTerminal ? stdout.terminalColumns : null;
4345

4446
typedef ConvertYamlToType<T> = T Function(YamlMap, String, ResourceProvider);
@@ -147,14 +149,22 @@ class ToolDefinition {
147149
List<String> command,
148150
List<String> setupCommand,
149151
String description,
150-
ResourceProvider resourceProvider) {
152+
ResourceProvider resourceProvider,
153+
{List<String> compileArgs}) {
151154
assert(command != null);
152155
assert(command.isNotEmpty);
153156
assert(description != null);
154157
if (isDartExecutable(command[0])) {
155158
return DartToolDefinition(
156-
command, setupCommand, description, resourceProvider);
159+
command, setupCommand, description, resourceProvider,
160+
compileArgs: compileArgs ?? const []);
157161
} else {
162+
if (compileArgs != null && compileArgs.isNotEmpty) {
163+
throw DartdocOptionError(
164+
'Compile arguments may only be specified for Dart tools, but '
165+
'$_kCompileArgsTagName of $compileArgs were specified for '
166+
'$command.');
167+
}
158168
return ToolDefinition(command, setupCommand, description);
159169
}
160170
}
@@ -274,6 +284,9 @@ class SnapshotCache {
274284
class DartToolDefinition extends ToolDefinition {
275285
final ResourceProvider _resourceProvider;
276286

287+
/// A list of arguments to add to the snapshot compilation arguments.
288+
final List<String> compileArgs;
289+
277290
/// Takes a list of args to modify, and returns the name of the executable
278291
/// to run. If no snapshot file existed, then create one and modify the args
279292
/// so that if they are executed with dart, will result in the snapshot being
@@ -295,7 +308,8 @@ class DartToolDefinition extends ToolDefinition {
295308
'--ignore-unrecognized-flags',
296309
'--verbosity=error',
297310
'--snapshot=${_resourceProvider.pathContext.absolute(snapshotFile.path)}',
298-
'--snapshot_kind=app-jit'
311+
'--snapshot_kind=app-jit',
312+
...compileArgs,
299313
]);
300314
} else {
301315
await snapshot.snapshotValid();
@@ -307,8 +321,10 @@ class DartToolDefinition extends ToolDefinition {
307321
}
308322

309323
DartToolDefinition(List<String> command, List<String> setupCommand,
310-
String description, this._resourceProvider)
311-
: super(command, setupCommand, description);
324+
String description, this._resourceProvider,
325+
{this.compileArgs = const []})
326+
: assert(compileArgs != null),
327+
super(command, setupCommand, description);
312328
}
313329

314330
/// A configuration class that can interpret [ToolDefinition]s from a YAML map.
@@ -335,6 +351,7 @@ class ToolConfiguration {
335351
for (var entry in yamlMap.entries) {
336352
var name = entry.key.toString();
337353
var toolMap = entry.value;
354+
List<String> compileArgs;
338355
String description;
339356
List<String> command;
340357
List<String> setupCommand;
@@ -343,39 +360,60 @@ class ToolConfiguration {
343360
List<String> findCommand([String prefix = '']) {
344361
List<String> command;
345362
// If the command key is given, then it applies to all platforms.
346-
var commandFrom = toolMap.containsKey('${prefix}command')
363+
var commandFromKey = toolMap.containsKey('${prefix}command')
347364
? '${prefix}command'
348365
: '$prefix${Platform.operatingSystem}';
349-
if (toolMap.containsKey(commandFrom)) {
350-
if (toolMap[commandFrom].value is String) {
351-
command = [toolMap[commandFrom].toString()];
366+
if (toolMap.containsKey(commandFromKey)) {
367+
var commandFrom = toolMap[commandFromKey] as YamlNode;
368+
if (commandFrom.value is String) {
369+
command = [commandFrom.toString()];
352370
if (command[0].isEmpty) {
353371
throw DartdocOptionError(
354372
'Tool commands must not be empty. Tool $name command entry '
355-
'"$commandFrom" must contain at least one path.');
373+
'"$commandFromKey" must contain at least one path.');
356374
}
357-
} else if (toolMap[commandFrom] is YamlList) {
358-
command = (toolMap[commandFrom] as YamlList)
359-
.map<String>((node) => node.toString())
360-
.toList();
375+
} else if (commandFrom is YamlList) {
376+
command =
377+
commandFrom.map<String>((node) => node.toString()).toList();
361378
if (command.isEmpty) {
362379
throw DartdocOptionError(
363380
'Tool commands must not be empty. Tool $name command entry '
364-
'"$commandFrom" must contain at least one path.');
381+
'"$commandFromKey" must contain at least one path.');
365382
}
366383
} else {
367384
throw DartdocOptionError(
368385
'Tool commands must be a path to an executable, or a list of '
369386
'strings that starts with a path to an executable. '
370-
'The tool $name has a $commandFrom entry that is a '
371-
'${toolMap[commandFrom].runtimeType}');
387+
'The tool $name has a $commandFromKey entry that is a '
388+
'${commandFrom.runtimeType}');
372389
}
373390
}
374391
return command;
375392
}
376393

377394
command = findCommand();
378395
setupCommand = findCommand('setup_');
396+
397+
List<String> findArgs() {
398+
List<String> args;
399+
if (toolMap.containsKey(_kCompileArgsTagName)) {
400+
var compileArgs = toolMap[_kCompileArgsTagName];
401+
if (compileArgs is String) {
402+
args = [toolMap[_kCompileArgsTagName].toString()];
403+
} else if (compileArgs is YamlList) {
404+
args =
405+
compileArgs.map<String>((node) => node.toString()).toList();
406+
} else {
407+
throw DartdocOptionError(
408+
'Tool compile arguments must be a list of strings. The tool '
409+
'$name has a $_kCompileArgsTagName entry that is a '
410+
'${compileArgs.runtimeType}');
411+
}
412+
}
413+
return args;
414+
}
415+
416+
compileArgs = findArgs();
379417
} else {
380418
throw DartdocOptionError(
381419
'Tools must be defined as a map of tool names to definitions. Tool '
@@ -421,7 +459,8 @@ class ToolConfiguration {
421459
setupCommand;
422460
}
423461
newToolDefinitions[name] = ToolDefinition.fromCommand(
424-
[executable] + command, setupCommand, description, resourceProvider);
462+
[executable] + command, setupCommand, description, resourceProvider,
463+
compileArgs: compileArgs ?? const []);
425464
}
426465
return ToolConfiguration._(newToolDefinitions, resourceProvider);
427466
}
@@ -598,16 +637,17 @@ abstract class DartdocOption<T> {
598637
_OptionValueWithContext<Object> valueWithContext, String missingFilename);
599638

600639
/// Call [_onMissing] for every path that does not exist.
601-
void _validatePaths(_OptionValueWithContext<dynamic> valueWithContext) {
640+
void _validatePaths(_OptionValueWithContext<Object> valueWithContext) {
602641
if (!mustExist) return;
603642
assert(isDir || isFile);
604643
List<String> resolvedPaths;
605-
if (valueWithContext.value is String) {
644+
var value = valueWithContext.value;
645+
if (value is String) {
606646
resolvedPaths = [valueWithContext.resolvedValue];
607-
} else if (valueWithContext.value is List<String>) {
608-
resolvedPaths = valueWithContext.resolvedValue.toList();
609-
} else if (valueWithContext.value is Map<String, String>) {
610-
resolvedPaths = valueWithContext.resolvedValue.values.toList();
647+
} else if (value is List<String>) {
648+
resolvedPaths = valueWithContext.resolvedValue as List;
649+
} else if (value is Map<String, String>) {
650+
resolvedPaths = (valueWithContext.resolvedValue as Map).values.toList();
611651
} else {
612652
assert(
613653
false,
@@ -1120,19 +1160,18 @@ abstract class _DartdocFileOption<T> implements DartdocOption<T> {
11201160
_OptionValueWithContext<Object> _valueAtFromFile(Folder dir) {
11211161
var yamlFileData = _yamlAtDirectory(dir);
11221162
var contextPath = yamlFileData.canonicalDirectoryPath;
1123-
dynamic yamlData = yamlFileData.data ?? {};
1163+
Object yamlData = yamlFileData.data ?? {};
11241164
for (var key in keys) {
1125-
if (!yamlData.containsKey(key)) return null;
1126-
yamlData = yamlData[key] ?? {};
1165+
if (yamlData is Map && !yamlData.containsKey(key)) return null;
1166+
yamlData = (yamlData as Map)[key] ?? {};
11271167
}
11281168

1129-
dynamic returnData;
1169+
Object returnData;
11301170
if (_isListString) {
11311171
if (yamlData is YamlList) {
1132-
returnData = <String>[];
1133-
for (var item in yamlData) {
1134-
returnData.add(item.toString());
1135-
}
1172+
returnData = [
1173+
for (var item in yamlData) item.toString(),
1174+
];
11361175
}
11371176
} else if (yamlData is YamlMap) {
11381177
// TODO(jcollins-g): This special casing is unfortunate. Consider
@@ -1700,7 +1739,7 @@ Future<List<DartdocOption<Object>>> createDartdocOptions(
17001739
help: 'Generate ONLY the docs for the Dart SDK.'),
17011740
DartdocOptionArgSynth<String>('sdkDir',
17021741
(DartdocSyntheticOption<String> option, Folder dir) {
1703-
if (!option.parent['sdkDocs'].valueAt(dir) &&
1742+
if (!(option.parent['sdkDocs'].valueAt(dir) as bool) &&
17041743
(option.root['topLevelPackageMeta'].valueAt(dir) as PackageMeta)
17051744
.requiresFlutter) {
17061745
String flutterRoot = option.root['flutterRoot'].valueAt(dir);

lib/src/model/accessor.dart

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,8 @@ class Accessor extends ModelElement implements EnclosedElement {
2626
ExecutableMember get originalMember => super.originalMember;
2727

2828
CallableElementTypeMixin _modelType;
29-
CallableElementTypeMixin get modelType {
30-
if (_modelType == null) {
31-
if (originalMember != null) {
32-
_modelType =
33-
ElementType.from(originalMember.type, library, packageGraph);
34-
} else {
35-
_modelType = ElementType.from(element.type, library, packageGraph);
36-
}
37-
}
38-
return _modelType;
39-
}
29+
CallableElementTypeMixin get modelType => _modelType ??=
30+
ElementType.from((originalMember ?? element).type, library, packageGraph);
4031

4132
bool get isSynthetic => element.isSynthetic;
4233

lib/src/model/documentation_comment.dart

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,11 +191,14 @@ mixin DocumentationComment
191191
/// ```yaml
192192
/// dartdoc:
193193
/// tools:
194-
/// # Prefixes the given input with "## "
195-
/// # Path is relative to project root.
196-
/// prefix: "bin/prefix.dart"
197-
/// # Prints the date
198-
/// date: "/bin/date"
194+
/// prefix:
195+
/// # Path is relative to project root.
196+
/// command: ["bin/prefix.dart"]
197+
/// description: "Prefixes the given input with '##'."
198+
/// compile_args: ["--no-sound-null-safety"]
199+
/// date:
200+
/// command: ["/bin/date"]
201+
/// description: "Prints the date"
199202
/// ```
200203
///
201204
/// In code:

lib/src/model/method.dart

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,17 +97,8 @@ class Method extends ModelElement
9797
ExecutableMember get originalMember => super.originalMember;
9898

9999
CallableElementTypeMixin _modelType;
100-
CallableElementTypeMixin get modelType {
101-
if (_modelType == null) {
102-
if (originalMember != null) {
103-
_modelType =
104-
ElementType.from(originalMember.type, library, packageGraph);
105-
} else {
106-
_modelType = ElementType.from(element.type, library, packageGraph);
107-
}
108-
}
109-
return _modelType;
110-
}
100+
CallableElementTypeMixin get modelType => _modelType ??=
101+
ElementType.from((originalMember ?? element).type, library, packageGraph);
111102

112103
@override
113104
Method get overriddenElement {

lib/src/model/model_element.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1056,7 +1056,7 @@ abstract class ModelElement extends Canonicalization
10561056
}
10571057
if (params == null && element is FunctionTypedElement) {
10581058
if (_originalMember != null) {
1059-
params = (_originalMember as dynamic).parameters;
1059+
params = (_originalMember as FunctionTypedElement).parameters;
10601060
} else {
10611061
params = (element as FunctionTypedElement).parameters;
10621062
}

lib/src/package_meta.dart

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,8 +379,12 @@ class _FilePackageMeta extends PubPackageMeta {
379379

380380
@override
381381
bool get requiresFlutter =>
382-
_pubspec['environment']?.containsKey('flutter') == true ||
383-
_pubspec['dependencies']?.containsKey('flutter') == true;
382+
_environment?.containsKey('flutter') == true ||
383+
_dependencies?.containsKey('flutter') == true;
384+
385+
YamlMap /*?*/ get _environment => _pubspec['environment'];
386+
387+
YamlMap /*?*/ get _dependencies => _pubspec['environment'];
384388

385389
@override
386390
File getReadmeContents() =>

test/dartdoc_options_test.dart

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ void main() {
6363
dartdocOptionSetSynthetic.add(
6464
DartdocOptionSyntheticOnly<List<String>>('vegetableLoader',
6565
(DartdocSyntheticOption<List<String>> option, Folder dir) {
66-
if (option.root['mySpecialInteger'].valueAt(dir) > 20) {
66+
if ((option.root['mySpecialInteger'].valueAt(dir) as num) > 20) {
6767
return <String>['existing.dart'];
6868
} else {
6969
return <String>['not_existing.dart'];
@@ -81,7 +81,7 @@ void main() {
8181
dartdocOptionSetSynthetic.add(
8282
DartdocOptionArgSynth<String>('nonCriticalFileOption',
8383
(DartdocSyntheticOption<String> option, Folder dir) {
84-
return option.root['vegetableLoader'].valueAt(dir).first;
84+
return (option.root['vegetableLoader'].valueAt(dir) as List).first;
8585
}, resourceProvider, optionIs: OptionKind.file));
8686

8787
dartdocOptionSetFiles = DartdocOptionSet('dartdoc', resourceProvider);
@@ -637,13 +637,13 @@ dartdoc:
637637
equals(
638638
'Field dartdoc.fileOptionList from ${path.canonicalize(dartdocOptionsTwo.path)}, set to [existing.dart, thing/that/does/not/exist], resolves to missing path: '
639639
'"${path.joinAll([
640-
path.canonicalize(secondDir.path),
641-
'thing',
642-
'that',
643-
'does',
644-
'not',
645-
'exist'
646-
])}"'));
640+
path.canonicalize(secondDir.path),
641+
'thing',
642+
'that',
643+
'does',
644+
'not',
645+
'exist'
646+
])}"'));
647647
// It doesn't matter that this fails.
648648
expect(dartdocOptionSetFiles['nonCriticalFileOption'].valueAt(firstDir),
649649
equals(path.joinAll([path.canonicalize(firstDir.path), 'whatever'])));
@@ -663,9 +663,9 @@ dartdoc:
663663
equals(
664664
'Field dartdoc.fileOption from ${path.canonicalize(dartdocOptionsTwo.path)}, set to not existing, resolves to missing path: '
665665
'"${path.joinAll([
666-
path.canonicalize(secondDir.path),
667-
"not existing"
668-
])}"'));
666+
path.canonicalize(secondDir.path),
667+
"not existing"
668+
])}"'));
669669
});
670670

671671
test('DartdocOptionSetFile works for directory options', () {

0 commit comments

Comments
 (0)