Skip to content

Data extraction from dartdoc internals. #1353

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 15, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ jobs:
script: ./tool/travis.sh test
env: PKG="pkg/_popularity"
dart: 2.0.0-dev.60.0
- stage: smoke_test
script: ./tool/travis.sh dartfmt dartanalyzer
env: PKG="pkg/pub_dartdoc"
dart: 2.0.0-dev.60.0
- stage: unit_test
script: ./tool/travis.sh test
env: PKG="pkg/pub_dartdoc"
dart: 2.0.0-dev.60.0

stages:
- smoke_test
Expand Down
11 changes: 11 additions & 0 deletions pkg/pub_dartdoc/.mono_repo.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# See https://github.com/dart-lang/mono_repo for details
dart:
- 2.0.0-dev.60.0

stages:
- smoke_test:
- group:
- dartfmt
- dartanalyzer: --fatal-infos --fatal-warnings .
- unit_test:
- test: --run-skipped
41 changes: 41 additions & 0 deletions pkg/pub_dartdoc/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
analyzer:
language:
enablePreviewDart2: true
strong-mode:
implicit-casts: false
errors:
dead_code: error
override_on_non_overriding_method: error
unused_element: error
unused_import: error
unused_local_variable: error
linter:
rules:
- avoid_empty_else
- avoid_init_to_null
- avoid_return_types_on_setters
- await_only_futures
- camel_case_types
- comment_references
- control_flow_in_finally
- directives_ordering
- empty_catches
- empty_constructor_bodies
- empty_statements
- hash_and_equals
- implementation_imports
- library_names
- library_prefixes
- non_constant_identifier_names
- omit_local_variable_types
- only_throw_errors
- prefer_final_fields
- prefer_is_not_empty
- prefer_single_quotes
- slash_for_doc_comments
- test_types_in_equals
- test_types_in_equals
- throw_in_finally
- type_init_formals
- unrelated_type_equality_checks
- valid_regexps
34 changes: 34 additions & 0 deletions pkg/pub_dartdoc/bin/pub_dartdoc.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:io';

import 'package:dartdoc/dartdoc.dart';
import 'package:dartdoc/src/html/html_generator.dart';
import 'package:dartdoc/src/logging.dart';

import 'package:pub_dartdoc/pub_data_generator.dart';

main(List<String> arguments) async {
final optionSet = await DartdocOptionSet.fromOptionGenerators('pub_dartdoc', [
createDartdocOptions,
createLoggingOptions,
createGeneratorOptions,
]);
optionSet.parseArguments(arguments);

final optionContext = new DartdocProgramOptionContext(optionSet, null);
startLogging(optionContext);

final dartdoc = await Dartdoc.withDefaultGenerators(optionContext);
dartdoc.generators.add(new PubDataGenerator(optionContext.inputDir));

await dartdoc.generateDocs();
}

class DartdocProgramOptionContext extends DartdocGeneratorOptionContext
with LoggingContext {
DartdocProgramOptionContext(DartdocOptionSet optionSet, Directory dir)
: super(optionSet, dir);
}
17 changes: 17 additions & 0 deletions pkg/pub_dartdoc/build.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Read about `build.yaml` at https://pub.dartlang.org/packages/build_config
# To update generated code, run `pub run build_runner build`
targets:
pub_dartdoc:
sources:
- 'lib/model.dart'
builders:
json_serializable:
options:
header: |+
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// GENERATED CODE - DO NOT MODIFY BY HAND

// ignore_for_file: prefer_final_locals
50 changes: 50 additions & 0 deletions pkg/pub_dartdoc/lib/model.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:json_annotation/json_annotation.dart';
import 'package:meta/meta.dart';

part 'model.g.dart';

@JsonSerializable()
class PubDartdocData extends Object with _$PubDartdocDataSerializerMixin {
final List<ApiElement> apiElements;

PubDartdocData({
@required this.apiElements,
});

factory PubDartdocData.fromJson(Map<String, dynamic> json) =>
_$PubDartdocDataFromJson(json);
}

@JsonSerializable()
class ApiElement extends Object with _$ApiElementSerializerMixin {
final String name;

final String kind;

@JsonKey(includeIfNull: false)
final String parent;

final String source;

@JsonKey(includeIfNull: false)
final String href;

@JsonKey(includeIfNull: false)
final String documentation;

ApiElement({
@required this.name,
@required this.kind,
@required this.parent,
@required this.source,
@required this.href,
@required this.documentation,
});

factory ApiElement.fromJson(Map<String, dynamic> json) =>
_$ApiElementFromJson(json);
}
65 changes: 65 additions & 0 deletions pkg/pub_dartdoc/lib/model.g.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

// GENERATED CODE - DO NOT MODIFY BY HAND

// ignore_for_file: prefer_final_locals

part of 'model.dart';

// **************************************************************************
// Generator: JsonSerializableGenerator
// **************************************************************************

PubDartdocData _$PubDartdocDataFromJson(Map<String, dynamic> json) {
return new PubDartdocData(
apiElements: (json['apiElements'] as List)
?.map((e) => e == null
? null
: new ApiElement.fromJson(e as Map<String, dynamic>))
?.toList());
}

abstract class _$PubDartdocDataSerializerMixin {
List<ApiElement> get apiElements;
Map<String, dynamic> toJson() =>
<String, dynamic>{'apiElements': apiElements};
}

ApiElement _$ApiElementFromJson(Map<String, dynamic> json) {
return new ApiElement(
name: json['name'] as String,
kind: json['kind'] as String,
parent: json['parent'] as String,
source: json['source'] as String,
href: json['href'] as String,
documentation: json['documentation'] as String);
}

abstract class _$ApiElementSerializerMixin {
String get name;
String get kind;
String get parent;
String get source;
String get href;
String get documentation;
Map<String, dynamic> toJson() {
var val = <String, dynamic>{
'name': name,
'kind': kind,
};

void writeNotNull(String key, dynamic value) {
if (value != null) {
val[key] = value;
}
}

writeNotNull('parent', parent);
val['source'] = source;
writeNotNull('href', href);
writeNotNull('documentation', documentation);
return val;
}
}
84 changes: 84 additions & 0 deletions pkg/pub_dartdoc/lib/pub_data_generator.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
// Copyright (c) 2018, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';
import 'dart:convert' as convert;
import 'dart:io';

import 'package:dartdoc/dartdoc.dart';
import 'package:path/path.dart' as p;

import 'model.dart';

const fileName = 'pub-data.json';

/// Generates `pub-data.json` in the output directory, containing the extracted
/// [PubDartdocData] instance.
class PubDataGenerator implements Generator {
final _onFileCreated = new StreamController<File>();
final _writtenFiles = new Set<String>();
final String _inputDirectory;

PubDataGenerator(this._inputDirectory);

@override
Future generate(PackageGraph packageGraph, String outputDirectoryPath) async {
final modelElements = packageGraph.allCanonicalModelElements
.where((elem) => elem.isPublic)
.where((elem) => p.isWithin(_inputDirectory, elem.sourceFileName))
.where((elem) {
// remove inherited items from dart:* libraries
final inheritedFrom = elem.overriddenElement?.fullyQualifiedName;
final fromDartLibs =
inheritedFrom != null && inheritedFrom.startsWith('dart:');
return !fromDartLibs;
}).toList();

final apiMap = <String, ApiElement>{};
void addElement(ModelElement elem) {
apiMap.putIfAbsent(
elem.fullyQualifiedName,
() => new ApiElement(
name: elem.fullyQualifiedName,
kind: elem.kind,
parent: elem.enclosingElement?.fullyQualifiedName,
source: p.relative(elem.sourceFileName, from: _inputDirectory),
href: _trimToNull(elem.href),
documentation: _trimToNull(elem.documentation),
));
if (elem.enclosingElement is ModelElement) {
addElement(elem.enclosingElement as ModelElement);
}
}

modelElements.forEach(addElement);

final apiElements = apiMap.values.toList();
apiElements.sort((a, b) {
if (a.parent == null && b.parent != null) return -1;
if (a.parent != null && b.parent == null) return 1;
if (a.parent != b.parent) return a.parent.compareTo(b.parent);
return a.name.compareTo(b.name);
});

final extract = new PubDartdocData(apiElements: apiElements);

final fileName = 'pub-data.json';
final outputFile = new File(p.join(outputDirectoryPath, fileName));
await outputFile.writeAsString(convert.json.encode(extract.toJson()));
_onFileCreated.add(outputFile);
_writtenFiles.add(fileName);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you mean outputFile?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wasn't sure about that either, the API documentation didn't specify it exactly, but package:dartdoc uses the same relative path pattern, and I'd go with that.

}

@override
Stream<File> get onFileCreated => _onFileCreated.stream;

@override
Set<String> get writtenFiles => _writtenFiles;
}

String _trimToNull(String text) {
text = text?.trim();
return (text != null && text.isEmpty) ? null : text;
}
Loading