From 6c6f26a6ea2985cd1f8f039a767ce2958ba94051 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Fri, 25 Mar 2022 15:40:07 +0000 Subject: [PATCH 01/41] feat: start setting up typedoc cli --- packages/dart_cli/bin/docs_page.dart | 45 +------- packages/dart_cli/lib/build_api_mdx.dart | 67 +++++++++++ packages/dart_cli/lib/create_files.dart | 44 +++++++ packages/dart_cli/pubspec.lock | 140 +++++++++++++++++++++++ packages/dart_cli/pubspec.yaml | 2 + 5 files changed, 254 insertions(+), 44 deletions(-) create mode 100644 packages/dart_cli/lib/build_api_mdx.dart create mode 100644 packages/dart_cli/lib/create_files.dart diff --git a/packages/dart_cli/bin/docs_page.dart b/packages/dart_cli/bin/docs_page.dart index 14fe0a5d..1be4e383 100644 --- a/packages/dart_cli/bin/docs_page.dart +++ b/packages/dart_cli/bin/docs_page.dart @@ -1,7 +1,5 @@ import 'package:args/args.dart'; -import 'dart:io'; -import 'package:path/path.dart' as path; -import 'package:ansi_styles/extension.dart'; +import 'package:docs_page/create_files.dart'; void main(List arguments) async { final parser = ArgParser(); @@ -13,44 +11,3 @@ void main(List arguments) async { throw UnsupportedError('Only the init command is currently supported.'); } } - -createFiles() async { - final indexContent = '# Welcome to your new documentation!'; - final configContent = ''' ---- -name: '' -logo: '' -logoDark: '' -favicon: '' -socialPreview: '' -twitter: '' -noindex: false -theme: "#00bcd4" -sidebar: [] -headerDepth: 3 -variables: {} -googleTagManager: '' -zoomImages: false -experimentalCodehike: false -experimentalMath: false -'''; - - final current = Directory.current; - - final configPath = path.joinAll([current.path, 'docs.yaml']); - - File configFile = await File(configPath).create(recursive: true); - - await configFile.writeAsString(configContent); - - final indexPath = path.joinAll([current.path, 'docs', 'index.mdx']); - - File indexFile = await File(indexPath).create(recursive: true); - - await indexFile.writeAsString(indexContent); - - print('Docs.page created files: \n $configPath \n $indexPath'.blueBright); - print( - 'To learn more about config file options and how customize your Docs.page project, visit ' + - "https://use.docs.page".underline.blueBright); -} diff --git a/packages/dart_cli/lib/build_api_mdx.dart b/packages/dart_cli/lib/build_api_mdx.dart new file mode 100644 index 00000000..231c24aa --- /dev/null +++ b/packages/dart_cli/lib/build_api_mdx.dart @@ -0,0 +1,67 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'build_api_mdx.g.dart'; + +@JsonSerializable() +class Node { + /// The generated code assumes these values exist in JSON. + final int id; + final String name; + final int kind; + final String? kindString; + final Map flags; + final List children; + final List groups; + final List? sources; + + Node({ + required this.id, + required this.name, + required this.kind, + required this.flags, + required this.children, + required this.groups, + this.kindString, + this.sources, + }); + + /// Connect the generated [_$PersonFromJson] function to the `fromJson` + /// factory. + factory Node.fromJson(Map json) => _$NodeFromJson(json); + + /// Connect the generated [_$PersonToJson] function to the `toJson` method. + Map toJson() => _$NodeToJson(this); +} + +@JsonSerializable() +class Group { + final String title; + final int kind; + final List children; + + Group({required this.title, required this.kind, required this.children}); + + factory Group.fromJson(Map json) => _$GroupFromJson(json); + + /// Connect the generated [_$PersonToJson] function to the `toJson` method. + Map toJson() => _$GroupToJson(this); +} + +@JsonSerializable() +class Source { + final String fileName; + final int line; + final List character; + + Source({required this.fileName, required this.line, required this.character}); + + factory Source.fromJson(Map json) => _$SourceFromJson(json); + + /// Connect the generated [_$PersonToJson] function to the `toJson` method. + Map toJson() => _$SourceToJson(this); +} + +// TODO +// get the typedoc.json from the repo +// parse it +// build mdx files from it for each of the types \ No newline at end of file diff --git a/packages/dart_cli/lib/create_files.dart b/packages/dart_cli/lib/create_files.dart new file mode 100644 index 00000000..14f1ab5b --- /dev/null +++ b/packages/dart_cli/lib/create_files.dart @@ -0,0 +1,44 @@ +import 'dart:io'; +import 'package:path/path.dart' as path; +import 'package:ansi_styles/extension.dart'; + +createFiles() async { + final indexContent = '# Welcome to your new documentation!'; + final configContent = ''' +--- +name: '' +logo: '' +logoDark: '' +favicon: '' +socialPreview: '' +twitter: '' +noindex: false +theme: "#00bcd4" +sidebar: [] +headerDepth: 3 +variables: {} +googleTagManager: '' +zoomImages: false +experimentalCodehike: false +experimentalMath: false +'''; + + final current = Directory.current; + + final configPath = path.joinAll([current.path, 'docs.yaml']); + + File configFile = await File(configPath).create(recursive: true); + + await configFile.writeAsString(configContent); + + final indexPath = path.joinAll([current.path, 'docs', 'index.mdx']); + + File indexFile = await File(indexPath).create(recursive: true); + + await indexFile.writeAsString(indexContent); + + print('Docs.page created files: \n $configPath \n $indexPath'.blueBright); + print( + 'To learn more about config file options and how customize your Docs.page project, visit ' + + "https://use.docs.page".underline.blueBright); +} diff --git a/packages/dart_cli/pubspec.lock b/packages/dart_cli/pubspec.lock index 4e38d520..d3b61577 100644 --- a/packages/dart_cli/pubspec.lock +++ b/packages/dart_cli/pubspec.lock @@ -43,6 +43,62 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + build: + dependency: transitive + description: + name: build + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.1" + build_config: + dependency: transitive + description: + name: build_config + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" + build_daemon: + dependency: transitive + description: + name: build_daemon + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1" + build_resolvers: + dependency: transitive + description: + name: build_resolvers + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.6" + build_runner: + dependency: "direct dev" + description: + name: build_runner + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.8" + build_runner_core: + dependency: transitive + description: + name: build_runner_core + url: "https://pub.dartlang.org" + source: hosted + version: "7.2.3" + built_collection: + dependency: transitive + description: + name: built_collection + url: "https://pub.dartlang.org" + source: hosted + version: "5.1.1" + built_value: + dependency: transitive + description: + name: built_value + url: "https://pub.dartlang.org" + source: hosted + version: "8.1.4" charcode: dependency: transitive description: @@ -50,6 +106,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.3.1" + checked_yaml: + dependency: transitive + description: + name: checked_yaml + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.1" + code_builder: + dependency: transitive + description: + name: code_builder + url: "https://pub.dartlang.org" + source: hosted + version: "4.1.0" collection: dependency: transitive description: @@ -78,6 +148,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.1" + dart_style: + dependency: transitive + description: + name: dart_style + url: "https://pub.dartlang.org" + source: hosted + version: "2.2.2" file: dependency: transitive description: @@ -85,6 +162,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.1.2" + fixnum: + dependency: transitive + description: + name: fixnum + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" frontend_server_client: dependency: transitive description: @@ -99,6 +183,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.0.2" + graphs: + dependency: transitive + description: + name: graphs + url: "https://pub.dartlang.org" + source: hosted + version: "2.1.0" http_multi_server: dependency: transitive description: @@ -127,6 +218,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.6.4" + json_annotation: + dependency: transitive + description: + name: json_annotation + url: "https://pub.dartlang.org" + source: hosted + version: "4.4.0" + json_serializable: + dependency: "direct main" + description: + name: json_serializable + url: "https://pub.dartlang.org" + source: hosted + version: "6.1.5" lints: dependency: "direct dev" description: @@ -197,6 +302,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.1" + pubspec_parse: + dependency: transitive + description: + name: pubspec_parse + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.0" shelf: dependency: transitive description: @@ -225,6 +337,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.1" + source_gen: + dependency: transitive + description: + name: source_gen + url: "https://pub.dartlang.org" + source: hosted + version: "1.2.1" + source_helper: + dependency: transitive + description: + name: source_helper + url: "https://pub.dartlang.org" + source: hosted + version: "1.3.1" source_map_stack_trace: dependency: transitive description: @@ -260,6 +386,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "2.1.0" + stream_transform: + dependency: transitive + description: + name: stream_transform + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" string_scanner: dependency: transitive description: @@ -295,6 +428,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "0.4.11" + timing: + dependency: transitive + description: + name: timing + url: "https://pub.dartlang.org" + source: hosted + version: "1.0.0" typed_data: dependency: transitive description: diff --git a/packages/dart_cli/pubspec.yaml b/packages/dart_cli/pubspec.yaml index 9a967af1..65bda53b 100644 --- a/packages/dart_cli/pubspec.yaml +++ b/packages/dart_cli/pubspec.yaml @@ -9,11 +9,13 @@ environment: dependencies: ansi_styles: ^0.3.2+1 args: ^2.3.0 + json_serializable: ^6.1.5 path: ^1.8.1 dev_dependencies: lints: ^1.0.0 test: ^1.16.0 + build_runner: executables: docs_page: \ No newline at end of file From 42e8e16754e11404d86e33958b75e9e6712cc349 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Fri, 25 Mar 2022 15:43:18 +0000 Subject: [PATCH 02/41] chore: generate and rename typedoc parsing --- .../{build_api_mdx.dart => src/typedoc.dart} | 0 packages/dart_cli/lib/src/typedoc.g.dart | 61 +++++++++++++++++++ 2 files changed, 61 insertions(+) rename packages/dart_cli/lib/{build_api_mdx.dart => src/typedoc.dart} (100%) create mode 100644 packages/dart_cli/lib/src/typedoc.g.dart diff --git a/packages/dart_cli/lib/build_api_mdx.dart b/packages/dart_cli/lib/src/typedoc.dart similarity index 100% rename from packages/dart_cli/lib/build_api_mdx.dart rename to packages/dart_cli/lib/src/typedoc.dart diff --git a/packages/dart_cli/lib/src/typedoc.g.dart b/packages/dart_cli/lib/src/typedoc.g.dart new file mode 100644 index 00000000..52fd0686 --- /dev/null +++ b/packages/dart_cli/lib/src/typedoc.g.dart @@ -0,0 +1,61 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'build_api_mdx.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Node _$NodeFromJson(Map json) => Node( + id: json['id'] as int, + name: json['name'] as String, + kind: json['kind'] as int, + flags: Map.from(json['flags'] as Map), + children: (json['children'] as List) + .map((e) => Node.fromJson(e as Map)) + .toList(), + groups: (json['groups'] as List) + .map((e) => Group.fromJson(e as Map)) + .toList(), + kindString: json['kindString'] as String?, + sources: (json['sources'] as List?) + ?.map((e) => Source.fromJson(e as Map)) + .toList(), + ); + +Map _$NodeToJson(Node instance) => { + 'id': instance.id, + 'name': instance.name, + 'kind': instance.kind, + 'kindString': instance.kindString, + 'flags': instance.flags, + 'children': instance.children, + 'groups': instance.groups, + 'sources': instance.sources, + }; + +Group _$GroupFromJson(Map json) => Group( + title: json['title'] as String, + kind: json['kind'] as int, + children: + (json['children'] as List).map((e) => e as int).toList(), + ); + +Map _$GroupToJson(Group instance) => { + 'title': instance.title, + 'kind': instance.kind, + 'children': instance.children, + }; + +Source _$SourceFromJson(Map json) => Source( + fileName: json['fileName'] as String, + line: json['line'] as int, + character: + (json['character'] as List).map((e) => e as int).toList(), + ); + +Map _$SourceToJson(Source instance) => { + 'fileName': instance.fileName, + 'line': instance.line, + 'character': instance.character, + }; From ecae86863611d112b52f36975e9abafad105803c Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Fri, 25 Mar 2022 18:37:56 +0000 Subject: [PATCH 03/41] chore: add reader for typedoc --- .../dart_cli/lib/{ => src}/create_files.dart | 0 packages/dart_cli/lib/src/typedoc.dart | 20 +++++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) rename packages/dart_cli/lib/{ => src}/create_files.dart (100%) diff --git a/packages/dart_cli/lib/create_files.dart b/packages/dart_cli/lib/src/create_files.dart similarity index 100% rename from packages/dart_cli/lib/create_files.dart rename to packages/dart_cli/lib/src/create_files.dart diff --git a/packages/dart_cli/lib/src/typedoc.dart b/packages/dart_cli/lib/src/typedoc.dart index 231c24aa..0383eee4 100644 --- a/packages/dart_cli/lib/src/typedoc.dart +++ b/packages/dart_cli/lib/src/typedoc.dart @@ -1,6 +1,9 @@ import 'package:json_annotation/json_annotation.dart'; +import 'package:path/path.dart' as path; +import 'dart:io'; +import 'dart:convert'; -part 'build_api_mdx.g.dart'; +part 'typedoc.g.dart'; @JsonSerializable() class Node { @@ -61,7 +64,20 @@ class Source { Map toJson() => _$SourceToJson(this); } -// TODO // get the typedoc.json from the repo + +Future getJson() async { + final current = Directory.current; + + final jsonPath = path.joinAll([current.path, 'docs', 'typedoc.json']); + + File typedocFile = File(jsonPath); + + String typedocString = await typedocFile.readAsString(); + + Node parsed = Node.fromJson(jsonDecode(typedocString)); + + return parsed; +} // parse it // build mdx files from it for each of the types \ No newline at end of file From 9bf27fe781c01b2526e9cdb025d675d509378c5b Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Mon, 28 Mar 2022 16:35:29 +0100 Subject: [PATCH 04/41] chore: add class for config --- packages/dart_cli/bin/docs_page.dart | 20 +++- packages/dart_cli/example/main.dart | 0 packages/dart_cli/lib/src/config.dart | 69 +++++++++++++ packages/dart_cli/lib/src/config.g.dart | 42 ++++++++ packages/dart_cli/lib/src/typedoc.dart | 125 +++++++++++++++++++---- packages/dart_cli/lib/src/typedoc.g.dart | 51 +++++++-- packages/dart_cli/pubspec.lock | 21 ++++ packages/dart_cli/pubspec.yaml | 1 + 8 files changed, 291 insertions(+), 38 deletions(-) create mode 100644 packages/dart_cli/example/main.dart create mode 100644 packages/dart_cli/lib/src/config.dart create mode 100644 packages/dart_cli/lib/src/config.g.dart diff --git a/packages/dart_cli/bin/docs_page.dart b/packages/dart_cli/bin/docs_page.dart index 1be4e383..2947ce06 100644 --- a/packages/dart_cli/bin/docs_page.dart +++ b/packages/dart_cli/bin/docs_page.dart @@ -1,13 +1,23 @@ import 'package:args/args.dart'; -import 'package:docs_page/create_files.dart'; +import 'package:docs_page/src/create_files.dart'; +import 'package:docs_page/src/typedoc.dart'; void main(List arguments) async { final parser = ArgParser(); parser.addCommand('init'); + parser.addCommand('typedoc'); final argResults = parser.parse(arguments); - if (argResults.command?.name == 'init') { - await createFiles(); - } else { - throw UnsupportedError('Only the init command is currently supported.'); + + switch (argResults.command?.name) { + case 'init': + await createFiles(); + break; + case 'typedoc': + Node ast = await getJson(); + await generate(ast); + break; + + default: + throw UnsupportedError('Only the init command is currently supported.'); } } diff --git a/packages/dart_cli/example/main.dart b/packages/dart_cli/example/main.dart new file mode 100644 index 00000000..e69de29b diff --git a/packages/dart_cli/lib/src/config.dart b/packages/dart_cli/lib/src/config.dart new file mode 100644 index 00000000..096fa2eb --- /dev/null +++ b/packages/dart_cli/lib/src/config.dart @@ -0,0 +1,69 @@ +import 'dart:convert'; +import 'package:json_annotation/json_annotation.dart'; +import 'dart:io'; +import 'package:yaml/yaml.dart'; +import 'package:toml/toml.dart'; +import 'package:path/path.dart' as path; + +part 'config.g.dart'; + +@JsonSerializable() +class Config { + final String? name; + final String? theme; + final String? twitter; + final List? sidebar; + final DocSearch? docsearch; + final String? googleTagManager; + final bool? experimentalCodeHike; + final bool? experimentalMath; + + Config( + {this.name, + this.theme, + this.docsearch, + this.twitter, + this.sidebar, + this.googleTagManager, + this.experimentalCodeHike, + this.experimentalMath}); + + factory Config.fromJson(Map json) => _$ConfigFromJson(json); + + factory Config.fromDirectory({Directory? dir}) { + final directory = dir ?? Directory.current; + + String configJsonPath = path.joinAll([directory.path, 'docs.json']); + String configYamlPath = path.joinAll([directory.path, 'docs.yaml']); + String configTomlPath = path.joinAll([directory.path, 'docs.toml']); + + File configJson = File(configJsonPath); + File configYaml = File(configYamlPath); + File configToml = File(configTomlPath); + + if (configJson.existsSync()) { + return _$ConfigFromJson(jsonDecode(configJson.readAsStringSync())); + } else if (configYaml.existsSync()) { + return _$ConfigFromJson(jsonDecode(configYaml.readAsStringSync())); + } else if (configToml.existsSync()) { + return _$ConfigFromJson(jsonDecode(configToml.readAsStringSync())); + } else { + throw Exception("can't find config"); + } + } + + Map toJson() => _$ConfigToJson(this); +} + +@JsonSerializable() +class DocSearch { + final String apiKey; + final String indexName; + + DocSearch({required this.apiKey, required this.indexName}); + + factory DocSearch.fromJson(Map json) => + _$DocSearchFromJson(json); + + Map toJson() => _$DocSearchToJson(this); +} diff --git a/packages/dart_cli/lib/src/config.g.dart b/packages/dart_cli/lib/src/config.g.dart new file mode 100644 index 00000000..7282c739 --- /dev/null +++ b/packages/dart_cli/lib/src/config.g.dart @@ -0,0 +1,42 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'config.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +Config _$ConfigFromJson(Map json) => Config( + name: json['name'] as String?, + theme: json['theme'] as String?, + docsearch: json['docsearch'] == null + ? null + : DocSearch.fromJson(json['docsearch'] as Map), + twitter: json['twitter'] as String?, + sidebar: + (json['sidebar'] as List?)?.map((e) => e as Object).toList(), + googleTagManager: json['googleTagManager'] as String?, + experimentalCodeHike: json['experimentalCodeHike'] as bool?, + experimentalMath: json['experimentalMath'] as bool?, + ); + +Map _$ConfigToJson(Config instance) => { + 'name': instance.name, + 'theme': instance.theme, + 'twitter': instance.twitter, + 'sidebar': instance.sidebar, + 'docsearch': instance.docsearch, + 'googleTagManager': instance.googleTagManager, + 'experimentalCodeHike': instance.experimentalCodeHike, + 'experimentalMath': instance.experimentalMath, + }; + +DocSearch _$DocSearchFromJson(Map json) => DocSearch( + apiKey: json['apiKey'] as String, + indexName: json['indexName'] as String, + ); + +Map _$DocSearchToJson(DocSearch instance) => { + 'apiKey': instance.apiKey, + 'indexName': instance.indexName, + }; diff --git a/packages/dart_cli/lib/src/typedoc.dart b/packages/dart_cli/lib/src/typedoc.dart index 0383eee4..1df6bcc2 100644 --- a/packages/dart_cli/lib/src/typedoc.dart +++ b/packages/dart_cli/lib/src/typedoc.dart @@ -1,3 +1,4 @@ +import 'package:docs_page/src/config.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:path/path.dart' as path; import 'dart:io'; @@ -8,27 +9,28 @@ part 'typedoc.g.dart'; @JsonSerializable() class Node { /// The generated code assumes these values exist in JSON. - final int id; - final String name; - final int kind; + final int? id; + final String? name; + final int? kind; final String? kindString; - final Map flags; - final List children; - final List groups; + final Map? flags; + final List? children; + final List? groups; final List? sources; - - Node({ - required this.id, - required this.name, - required this.kind, - required this.flags, - required this.children, - required this.groups, - this.kindString, - this.sources, - }); - - /// Connect the generated [_$PersonFromJson] function to the `fromJson` + final Comment? comment; + + Node( + {this.id, + this.name, + this.kind, + this.flags, + this.children, + this.groups, + this.kindString, + this.sources, + this.comment}); + + /// Connect the generated [_$NodeFromJson] function to the `fromJson` /// factory. factory Node.fromJson(Map json) => _$NodeFromJson(json); @@ -46,7 +48,7 @@ class Group { factory Group.fromJson(Map json) => _$GroupFromJson(json); - /// Connect the generated [_$PersonToJson] function to the `toJson` method. + /// Connect the generated [_GroupToJson] function to the `toJson` method. Map toJson() => _$GroupToJson(this); } @@ -54,16 +56,43 @@ class Group { class Source { final String fileName; final int line; - final List character; + final int character; Source({required this.fileName, required this.line, required this.character}); factory Source.fromJson(Map json) => _$SourceFromJson(json); - /// Connect the generated [_$PersonToJson] function to the `toJson` method. + /// Connect the generated [_$SourceToJson] function to the `toJson` method. Map toJson() => _$SourceToJson(this); } +@JsonSerializable() +class Comment { + final String? shortText; + final String? text; + final List? tags; + + Comment({this.shortText, this.text, this.tags}); + + factory Comment.fromJson(Map json) => + _$CommentFromJson(json); + + /// Connect the generated [_$CommentToJson] function to the `toJson` method. + Map toJson() => _$CommentToJson(this); +} + +@JsonSerializable() +class Tag { + final String tag; + final String text; + + Tag({required this.tag, required this.text}); + + factory Tag.fromJson(Map json) => _$TagFromJson(json); + + /// Connect the generated [_$TagToJson] function to the `toJson` method. + Map toJson() => _$TagToJson(this); +} // get the typedoc.json from the repo Future getJson() async { @@ -80,4 +109,56 @@ Future getJson() async { return parsed; } // parse it + +Future generate(Node ast) async { + final current = Directory.current; + final groups = ast.groups; + final children = ast.children; + + if (groups != null && children != null && children.isNotEmpty) { + for (final group in groups) { + String filePath = + path.joinAll([current.path, 'docs', 'api', group.title + '.mdx']); + + File groupDoc = await File(filePath).create(recursive: true); + + await groupDoc.writeAsString('# ' + group.title + ' \n'); + final groupKind = group.kind; + + for (final child in children) { + final childKind = child.kind; + final childName = child.name; + final childShortText = + child.comment?.shortText?.replaceAll(RegExp('<.+>'), ''); + final childText = child.comment?.text?.replaceAll(RegExp('<.+>'), ''); + + if (childKind != null && childKind == groupKind && childName != null) { + await groupDoc.writeAsString('## ' + childName + ' \n ', + mode: FileMode.append); + if (childShortText != null) { + await groupDoc.writeAsString('\n **Description:** \n', + mode: FileMode.append); + await groupDoc.writeAsString('\n $childShortText \n', + mode: FileMode.append); + } + if (childText != null) { + await groupDoc.writeAsString('\n **Detail:** \n', + mode: FileMode.append); + await groupDoc.writeAsString('\n $childText \n', + mode: FileMode.append); + } + } + } + // create an mdx file called group.title + // populate with headings from node.children[group.children] + } + } +} + +Future appendToSidebar(String groupName) async { + final config = Config.fromDirectory(); +} + +// 1. separate into groups +// 2. just make headings for enums // build mdx files from it for each of the types \ No newline at end of file diff --git a/packages/dart_cli/lib/src/typedoc.g.dart b/packages/dart_cli/lib/src/typedoc.g.dart index 52fd0686..1eac5ae5 100644 --- a/packages/dart_cli/lib/src/typedoc.g.dart +++ b/packages/dart_cli/lib/src/typedoc.g.dart @@ -1,26 +1,31 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'build_api_mdx.dart'; +part of 'typedoc.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** Node _$NodeFromJson(Map json) => Node( - id: json['id'] as int, - name: json['name'] as String, - kind: json['kind'] as int, - flags: Map.from(json['flags'] as Map), - children: (json['children'] as List) - .map((e) => Node.fromJson(e as Map)) + id: json['id'] as int?, + name: json['name'] as String?, + kind: json['kind'] as int?, + flags: (json['flags'] as Map?)?.map( + (k, e) => MapEntry(k, e as bool), + ), + children: (json['children'] as List?) + ?.map((e) => Node.fromJson(e as Map)) .toList(), - groups: (json['groups'] as List) - .map((e) => Group.fromJson(e as Map)) + groups: (json['groups'] as List?) + ?.map((e) => Group.fromJson(e as Map)) .toList(), kindString: json['kindString'] as String?, sources: (json['sources'] as List?) ?.map((e) => Source.fromJson(e as Map)) .toList(), + comment: json['comment'] == null + ? null + : Comment.fromJson(json['comment'] as Map), ); Map _$NodeToJson(Node instance) => { @@ -32,6 +37,7 @@ Map _$NodeToJson(Node instance) => { 'children': instance.children, 'groups': instance.groups, 'sources': instance.sources, + 'comment': instance.comment, }; Group _$GroupFromJson(Map json) => Group( @@ -50,8 +56,7 @@ Map _$GroupToJson(Group instance) => { Source _$SourceFromJson(Map json) => Source( fileName: json['fileName'] as String, line: json['line'] as int, - character: - (json['character'] as List).map((e) => e as int).toList(), + character: json['character'] as int, ); Map _$SourceToJson(Source instance) => { @@ -59,3 +64,27 @@ Map _$SourceToJson(Source instance) => { 'line': instance.line, 'character': instance.character, }; + +Comment _$CommentFromJson(Map json) => Comment( + shortText: json['shortText'] as String?, + text: json['text'] as String?, + tags: (json['tags'] as List?) + ?.map((e) => Tag.fromJson(e as Map)) + .toList(), + ); + +Map _$CommentToJson(Comment instance) => { + 'shortText': instance.shortText, + 'text': instance.text, + 'tags': instance.tags, + }; + +Tag _$TagFromJson(Map json) => Tag( + tag: json['tag'] as String, + text: json['text'] as String, + ); + +Map _$TagToJson(Tag instance) => { + 'tag': instance.tag, + 'text': instance.text, + }; diff --git a/packages/dart_cli/pubspec.lock b/packages/dart_cli/pubspec.lock index d3b61577..091f538d 100644 --- a/packages/dart_cli/pubspec.lock +++ b/packages/dart_cli/pubspec.lock @@ -288,6 +288,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.8.1" + petitparser: + dependency: transitive + description: + name: petitparser + url: "https://pub.dartlang.org" + source: hosted + version: "4.4.0" pool: dependency: transitive description: @@ -309,6 +316,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.2.0" + quiver: + dependency: transitive + description: + name: quiver + url: "https://pub.dartlang.org" + source: hosted + version: "3.0.1+1" shelf: dependency: transitive description: @@ -435,6 +449,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" + toml: + dependency: "direct main" + description: + name: toml + url: "https://pub.dartlang.org" + source: hosted + version: "0.12.0" typed_data: dependency: transitive description: diff --git a/packages/dart_cli/pubspec.yaml b/packages/dart_cli/pubspec.yaml index 65bda53b..ed4542b2 100644 --- a/packages/dart_cli/pubspec.yaml +++ b/packages/dart_cli/pubspec.yaml @@ -11,6 +11,7 @@ dependencies: args: ^2.3.0 json_serializable: ^6.1.5 path: ^1.8.1 + toml: "^0.12.0" dev_dependencies: lints: ^1.0.0 From e57c6d934902773231b39d341bcf0359a9f357b4 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Tue, 29 Mar 2022 11:06:48 +0100 Subject: [PATCH 05/41] chore: generate docs.refs.json --- packages/dart_cli/.gitignore | 4 +- packages/dart_cli/example/main.dart | 7 +++ .../{config.dart => docs_page_config.dart} | 47 +++++++++++++++---- ...{config.g.dart => docs_page_config.g.dart} | 10 ++-- packages/dart_cli/lib/src/typedoc.dart | 29 ++++++++---- packages/dart_cli/pubspec.lock | 2 +- packages/dart_cli/pubspec.yaml | 1 + 7 files changed, 76 insertions(+), 24 deletions(-) rename packages/dart_cli/lib/src/{config.dart => docs_page_config.dart} (52%) rename packages/dart_cli/lib/src/{config.g.dart => docs_page_config.g.dart} (81%) diff --git a/packages/dart_cli/.gitignore b/packages/dart_cli/.gitignore index 50d967d8..e645ecf7 100644 --- a/packages/dart_cli/.gitignore +++ b/packages/dart_cli/.gitignore @@ -7,4 +7,6 @@ build/ # Created by running the command in this directory, don't commit docs.yaml -docs \ No newline at end of file +docs + +example \ No newline at end of file diff --git a/packages/dart_cli/example/main.dart b/packages/dart_cli/example/main.dart index e69de29b..52fefbcd 100644 --- a/packages/dart_cli/example/main.dart +++ b/packages/dart_cli/example/main.dart @@ -0,0 +1,7 @@ +import 'package:docs_page/src/typedoc.dart'; + +void main() async { + final rootAst = await getJson(); + + await generate(rootAst); +} diff --git a/packages/dart_cli/lib/src/config.dart b/packages/dart_cli/lib/src/docs_page_config.dart similarity index 52% rename from packages/dart_cli/lib/src/config.dart rename to packages/dart_cli/lib/src/docs_page_config.dart index 096fa2eb..e10f8384 100644 --- a/packages/dart_cli/lib/src/config.dart +++ b/packages/dart_cli/lib/src/docs_page_config.dart @@ -5,10 +5,10 @@ import 'package:yaml/yaml.dart'; import 'package:toml/toml.dart'; import 'package:path/path.dart' as path; -part 'config.g.dart'; +part 'docs_page_config.g.dart'; @JsonSerializable() -class Config { +class DocsPageConfig { final String? name; final String? theme; final String? twitter; @@ -17,8 +17,9 @@ class Config { final String? googleTagManager; final bool? experimentalCodeHike; final bool? experimentalMath; + final List? refs; - Config( + DocsPageConfig( {this.name, this.theme, this.docsearch, @@ -26,11 +27,13 @@ class Config { this.sidebar, this.googleTagManager, this.experimentalCodeHike, - this.experimentalMath}); + this.experimentalMath, + this.refs}); - factory Config.fromJson(Map json) => _$ConfigFromJson(json); + factory DocsPageConfig.fromJson(Map json) => + _$DocsPageConfigFromJson(json); - factory Config.fromDirectory({Directory? dir}) { + factory DocsPageConfig.fromDirectory({Directory? dir}) { final directory = dir ?? Directory.current; String configJsonPath = path.joinAll([directory.path, 'docs.json']); @@ -42,17 +45,41 @@ class Config { File configToml = File(configTomlPath); if (configJson.existsSync()) { - return _$ConfigFromJson(jsonDecode(configJson.readAsStringSync())); + return _$DocsPageConfigFromJson( + jsonDecode(configJson.readAsStringSync())); } else if (configYaml.existsSync()) { - return _$ConfigFromJson(jsonDecode(configYaml.readAsStringSync())); + return _$DocsPageConfigFromJson( + Map.from(loadYaml(configYaml.readAsStringSync()))); } else if (configToml.existsSync()) { - return _$ConfigFromJson(jsonDecode(configToml.readAsStringSync())); + return _$DocsPageConfigFromJson( + TomlDocument.parse(configToml.readAsStringSync()).toMap()); } else { throw Exception("can't find config"); } } - Map toJson() => _$ConfigToJson(this); + void overwriteInDirectory({Directory? dir, DocsPageConfig? config}) { + final directory = dir ?? Directory.current; + + String configJsonPath = path.joinAll([directory.path, 'docs.json']); + String configYamlPath = path.joinAll([directory.path, 'docs.yaml']); + + File configJson = File(configJsonPath); + File configYaml = File(configYamlPath); + final config = this; + + if (configJson.existsSync()) { + configJson.writeAsStringSync(json.encode(config)); + return; + } else if (configYaml.existsSync()) { + configJson.writeAsStringSync(json.encode(config)); + return; + } else { + throw UnsupportedError("Can only overwrite yaml and json formats"); + } + } + + Map toJson() => _$DocsPageConfigToJson(this); } @JsonSerializable() diff --git a/packages/dart_cli/lib/src/config.g.dart b/packages/dart_cli/lib/src/docs_page_config.g.dart similarity index 81% rename from packages/dart_cli/lib/src/config.g.dart rename to packages/dart_cli/lib/src/docs_page_config.g.dart index 7282c739..26715dd7 100644 --- a/packages/dart_cli/lib/src/config.g.dart +++ b/packages/dart_cli/lib/src/docs_page_config.g.dart @@ -1,12 +1,13 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'config.dart'; +part of 'docs_page_config.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** -Config _$ConfigFromJson(Map json) => Config( +DocsPageConfig _$DocsPageConfigFromJson(Map json) => + DocsPageConfig( name: json['name'] as String?, theme: json['theme'] as String?, docsearch: json['docsearch'] == null @@ -18,9 +19,11 @@ Config _$ConfigFromJson(Map json) => Config( googleTagManager: json['googleTagManager'] as String?, experimentalCodeHike: json['experimentalCodeHike'] as bool?, experimentalMath: json['experimentalMath'] as bool?, + refs: (json['refs'] as List?)?.map((e) => e as Object).toList(), ); -Map _$ConfigToJson(Config instance) => { +Map _$DocsPageConfigToJson(DocsPageConfig instance) => + { 'name': instance.name, 'theme': instance.theme, 'twitter': instance.twitter, @@ -29,6 +32,7 @@ Map _$ConfigToJson(Config instance) => { 'googleTagManager': instance.googleTagManager, 'experimentalCodeHike': instance.experimentalCodeHike, 'experimentalMath': instance.experimentalMath, + 'refs': instance.refs, }; DocSearch _$DocSearchFromJson(Map json) => DocSearch( diff --git a/packages/dart_cli/lib/src/typedoc.dart b/packages/dart_cli/lib/src/typedoc.dart index 1df6bcc2..95a1683e 100644 --- a/packages/dart_cli/lib/src/typedoc.dart +++ b/packages/dart_cli/lib/src/typedoc.dart @@ -1,4 +1,4 @@ -import 'package:docs_page/src/config.dart'; +import 'package:docs_page/src/docs_page_config.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:path/path.dart' as path; import 'dart:io'; @@ -149,16 +149,27 @@ Future generate(Node ast) async { } } } - // create an mdx file called group.title - // populate with headings from node.children[group.children] } + await appendToSidebar(ast); } } -Future appendToSidebar(String groupName) async { - final config = Config.fromDirectory(); -} +Future appendToSidebar(Node rootAst) async { + final groups = rootAst.groups; + if (groups == null) { + throw Exception('No groups found'); + } + List refs = []; + + for (final group in groups) { + final href = Uri.encodeFull(group.title); + + List refItem = [group.title, '/_API/$href']; -// 1. separate into groups -// 2. just make headings for enums -// build mdx files from it for each of the types \ No newline at end of file + refs.add(refItem); + } + + final refsPath = path.joinAll([Directory.current.path, 'docs.refs.json']); + + File(refsPath).writeAsStringSync(json.encode(refs)); +} diff --git a/packages/dart_cli/pubspec.lock b/packages/dart_cli/pubspec.lock index 091f538d..07ae5b8f 100644 --- a/packages/dart_cli/pubspec.lock +++ b/packages/dart_cli/pubspec.lock @@ -219,7 +219,7 @@ packages: source: hosted version: "0.6.4" json_annotation: - dependency: transitive + dependency: "direct main" description: name: json_annotation url: "https://pub.dartlang.org" diff --git a/packages/dart_cli/pubspec.yaml b/packages/dart_cli/pubspec.yaml index ed4542b2..1ea9f292 100644 --- a/packages/dart_cli/pubspec.yaml +++ b/packages/dart_cli/pubspec.yaml @@ -10,6 +10,7 @@ dependencies: ansi_styles: ^0.3.2+1 args: ^2.3.0 json_serializable: ^6.1.5 + json_annotation: ^4.4.0 path: ^1.8.1 toml: "^0.12.0" From c9d021f0808fd69e838d8ed160d1faa836679f85 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Tue, 29 Mar 2022 13:08:10 +0100 Subject: [PATCH 06/41] chore: generate a page for each reference --- packages/dart_cli/example/main.dart | 4 +- packages/dart_cli/lib/src/typedoc.dart | 70 +++++++++++++----------- packages/dart_cli/lib/src/typedoc.g.dart | 2 +- 3 files changed, 41 insertions(+), 35 deletions(-) diff --git a/packages/dart_cli/example/main.dart b/packages/dart_cli/example/main.dart index 52fefbcd..f070ad11 100644 --- a/packages/dart_cli/example/main.dart +++ b/packages/dart_cli/example/main.dart @@ -1,7 +1,9 @@ +import 'dart:io'; + import 'package:docs_page/src/typedoc.dart'; void main() async { final rootAst = await getJson(); - await generate(rootAst); + await generate(ast: rootAst); } diff --git a/packages/dart_cli/lib/src/typedoc.dart b/packages/dart_cli/lib/src/typedoc.dart index 95a1683e..7029d104 100644 --- a/packages/dart_cli/lib/src/typedoc.dart +++ b/packages/dart_cli/lib/src/typedoc.dart @@ -10,7 +10,7 @@ part 'typedoc.g.dart'; class Node { /// The generated code assumes these values exist in JSON. final int? id; - final String? name; + final String name; final int? kind; final String? kindString; final Map? flags; @@ -21,7 +21,7 @@ class Node { Node( {this.id, - this.name, + required this.name, this.kind, this.flags, this.children, @@ -110,47 +110,51 @@ Future getJson() async { } // parse it -Future generate(Node ast) async { - final current = Directory.current; +Future generate({required Node ast, String? docPath}) async { + String currentPath = + docPath ?? path.joinAll([Directory.current.path, 'docs', '_API']); final groups = ast.groups; final children = ast.children; - if (groups != null && children != null && children.isNotEmpty) { - for (final group in groups) { - String filePath = - path.joinAll([current.path, 'docs', 'api', group.title + '.mdx']); + List refs = []; - File groupDoc = await File(filePath).create(recursive: true); +// If there are more than one group defined, make a subdirectory and continue recursively + if (groups != null && + children != null && + children.isNotEmpty && + groups.length > 1) { + for (final group in groups) { + // Make a directory group.title + String dirPath = path.joinAll([currentPath, group.title]); - await groupDoc.writeAsString('# ' + group.title + ' \n'); - final groupKind = group.kind; + await Directory(dirPath).create(recursive: true); + // go through ast.children and call generate on them with new path + for (final child in children) { + await generate(ast: child, docPath: dirPath); + } + } + } else { + // otherwise create file from node + final filePath = path.joinAll([currentPath, '${ast.name}.mdx']); + // title + await File(filePath) + .writeAsString("# ${ast.name} \n \n", mode: FileMode.append); + // description + await File(filePath) + .writeAsString("**Description**: \n \n", mode: FileMode.append); + final shortText = ast.comment?.shortText; + if (shortText != null) { + await File(filePath) + .writeAsString("$shortText \n \n", mode: FileMode.append); + } + if (children != null && children.isNotEmpty) { for (final child in children) { - final childKind = child.kind; final childName = child.name; - final childShortText = - child.comment?.shortText?.replaceAll(RegExp('<.+>'), ''); - final childText = child.comment?.text?.replaceAll(RegExp('<.+>'), ''); - - if (childKind != null && childKind == groupKind && childName != null) { - await groupDoc.writeAsString('## ' + childName + ' \n ', - mode: FileMode.append); - if (childShortText != null) { - await groupDoc.writeAsString('\n **Description:** \n', - mode: FileMode.append); - await groupDoc.writeAsString('\n $childShortText \n', - mode: FileMode.append); - } - if (childText != null) { - await groupDoc.writeAsString('\n **Detail:** \n', - mode: FileMode.append); - await groupDoc.writeAsString('\n $childText \n', - mode: FileMode.append); - } - } + await File(filePath) + .writeAsString("child: $childName \n", mode: FileMode.append); } } - await appendToSidebar(ast); } } diff --git a/packages/dart_cli/lib/src/typedoc.g.dart b/packages/dart_cli/lib/src/typedoc.g.dart index 1eac5ae5..39ffd573 100644 --- a/packages/dart_cli/lib/src/typedoc.g.dart +++ b/packages/dart_cli/lib/src/typedoc.g.dart @@ -8,7 +8,7 @@ part of 'typedoc.dart'; Node _$NodeFromJson(Map json) => Node( id: json['id'] as int?, - name: json['name'] as String?, + name: json['name'] as String, kind: json['kind'] as int?, flags: (json['flags'] as Map?)?.map( (k, e) => MapEntry(k, e as bool), From 445e0fd78d505466c18b2d5c7760ce493de2dc0d Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Tue, 29 Mar 2022 15:18:00 +0100 Subject: [PATCH 07/41] chore: generate the reference json --- packages/dart_cli/bin/docs_page.dart | 2 +- .../dart_cli/lib/src/docs_page_config.dart | 4 +- .../dart_cli/lib/src/docs_page_config.g.dart | 4 +- packages/dart_cli/lib/src/typedoc.dart | 91 ++++++++----------- 4 files changed, 44 insertions(+), 57 deletions(-) diff --git a/packages/dart_cli/bin/docs_page.dart b/packages/dart_cli/bin/docs_page.dart index 2947ce06..23a05c8a 100644 --- a/packages/dart_cli/bin/docs_page.dart +++ b/packages/dart_cli/bin/docs_page.dart @@ -14,7 +14,7 @@ void main(List arguments) async { break; case 'typedoc': Node ast = await getJson(); - await generate(ast); + await generate(ast: ast); break; default: diff --git a/packages/dart_cli/lib/src/docs_page_config.dart b/packages/dart_cli/lib/src/docs_page_config.dart index e10f8384..01c95087 100644 --- a/packages/dart_cli/lib/src/docs_page_config.dart +++ b/packages/dart_cli/lib/src/docs_page_config.dart @@ -17,7 +17,7 @@ class DocsPageConfig { final String? googleTagManager; final bool? experimentalCodeHike; final bool? experimentalMath; - final List? refs; + final String? references; DocsPageConfig( {this.name, @@ -28,7 +28,7 @@ class DocsPageConfig { this.googleTagManager, this.experimentalCodeHike, this.experimentalMath, - this.refs}); + this.references}); factory DocsPageConfig.fromJson(Map json) => _$DocsPageConfigFromJson(json); diff --git a/packages/dart_cli/lib/src/docs_page_config.g.dart b/packages/dart_cli/lib/src/docs_page_config.g.dart index 26715dd7..194ef875 100644 --- a/packages/dart_cli/lib/src/docs_page_config.g.dart +++ b/packages/dart_cli/lib/src/docs_page_config.g.dart @@ -19,7 +19,7 @@ DocsPageConfig _$DocsPageConfigFromJson(Map json) => googleTagManager: json['googleTagManager'] as String?, experimentalCodeHike: json['experimentalCodeHike'] as bool?, experimentalMath: json['experimentalMath'] as bool?, - refs: (json['refs'] as List?)?.map((e) => e as Object).toList(), + references: json['references'] as String?, ); Map _$DocsPageConfigToJson(DocsPageConfig instance) => @@ -32,7 +32,7 @@ Map _$DocsPageConfigToJson(DocsPageConfig instance) => 'googleTagManager': instance.googleTagManager, 'experimentalCodeHike': instance.experimentalCodeHike, 'experimentalMath': instance.experimentalMath, - 'refs': instance.refs, + 'references': instance.references, }; DocSearch _$DocSearchFromJson(Map json) => DocSearch( diff --git a/packages/dart_cli/lib/src/typedoc.dart b/packages/dart_cli/lib/src/typedoc.dart index 7029d104..021e381b 100644 --- a/packages/dart_cli/lib/src/typedoc.dart +++ b/packages/dart_cli/lib/src/typedoc.dart @@ -108,72 +108,59 @@ Future getJson() async { return parsed; } + // parse it -Future generate({required Node ast, String? docPath}) async { +Future generate( + {required Node ast, String? docPath, List? refs}) async { + DocsPageConfig config = DocsPageConfig.fromDirectory(); + + String referenceRoot = config.references ?? '_API'; + String currentPath = - docPath ?? path.joinAll([Directory.current.path, 'docs', '_API']); + docPath ?? path.joinAll([Directory.current.path, 'docs', referenceRoot]); final groups = ast.groups; final children = ast.children; - List refs = []; - -// If there are more than one group defined, make a subdirectory and continue recursively - if (groups != null && - children != null && - children.isNotEmpty && - groups.length > 1) { - for (final group in groups) { - // Make a directory group.title - String dirPath = path.joinAll([currentPath, group.title]); - - await Directory(dirPath).create(recursive: true); - - // go through ast.children and call generate on them with new path - for (final child in children) { - await generate(ast: child, docPath: dirPath); - } - } - } else { - // otherwise create file from node - final filePath = path.joinAll([currentPath, '${ast.name}.mdx']); - // title - await File(filePath) - .writeAsString("# ${ast.name} \n \n", mode: FileMode.append); - // description - await File(filePath) - .writeAsString("**Description**: \n \n", mode: FileMode.append); - final shortText = ast.comment?.shortText; - if (shortText != null) { - await File(filePath) - .writeAsString("$shortText \n \n", mode: FileMode.append); - } - if (children != null && children.isNotEmpty) { - for (final child in children) { - final childName = child.name; - await File(filePath) - .writeAsString("child: $childName \n", mode: FileMode.append); - } + if (children != null && children.isNotEmpty) { + for (final child in children) { + final childPath = path.joinAll([currentPath, '${child.name}.mdx']); + final refPath = path.joinAll([currentPath, child.name]); + await addRef(child.name, refPath); + await createDoc(child, childPath); } } } -Future appendToSidebar(Node rootAst) async { - final groups = rootAst.groups; - if (groups == null) { - throw Exception('No groups found'); +Future addRef(String name, String filePath) async { + File refsFile = + File(path.joinAll([Directory.current.path, 'docs.refs.json'])); + + String refsString = "[]"; + + if (await refsFile.exists()) { + refsString = await refsFile.readAsString(); } - List refs = []; - for (final group in groups) { - final href = Uri.encodeFull(group.title); + List refs = jsonDecode(refsString); - List refItem = [group.title, '/_API/$href']; + refs.add([name, Uri.encodeFull(filePath)]); - refs.add(refItem); - } + refsFile.writeAsString(json.encode(refs)); +} + +Future createDoc(Node node, String childPath) async { + File file = await File(childPath).create(recursive: true); + String frontmatter = ''' +--- +title: ${node.name} +description: ${node.comment?.shortText} +reference: true +--- +'''; - final refsPath = path.joinAll([Directory.current.path, 'docs.refs.json']); + await file.writeAsString(frontmatter); + await file.writeAsString('\n \n', mode: FileMode.append); - File(refsPath).writeAsStringSync(json.encode(refs)); + await file.writeAsString('# ${node.name} \n \n', mode: FileMode.append); } From 8a3dfd602b4d4e97074974e75be9bfdd6e64cbb9 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Tue, 29 Mar 2022 16:09:25 +0100 Subject: [PATCH 08/41] chore: update format of docs.refs.json --- packages/dart_cli/lib/src/typedoc.dart | 39 ++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 6 deletions(-) diff --git a/packages/dart_cli/lib/src/typedoc.dart b/packages/dart_cli/lib/src/typedoc.dart index 021e381b..13ef344c 100644 --- a/packages/dart_cli/lib/src/typedoc.dart +++ b/packages/dart_cli/lib/src/typedoc.dart @@ -119,32 +119,47 @@ Future generate( String currentPath = docPath ?? path.joinAll([Directory.current.path, 'docs', referenceRoot]); - final groups = ast.groups; + final children = ast.children; + File refsFile = + File(path.joinAll([Directory.current.path, 'docs.refs.json'])); + + refsFile.delete(recursive: true); + if (children != null && children.isNotEmpty) { for (final child in children) { final childPath = path.joinAll([currentPath, '${child.name}.mdx']); - final refPath = path.joinAll([currentPath, child.name]); - await addRef(child.name, refPath); + + final refPath = path.relative(path.joinAll([currentPath, child.name]), + from: path.joinAll([Directory.current.path, 'docs'])); + + await addRef(child, refPath); + await createDoc(child, childPath); } } } -Future addRef(String name, String filePath) async { +Future addRef(Node node, String filePath) async { File refsFile = File(path.joinAll([Directory.current.path, 'docs.refs.json'])); String refsString = "[]"; - if (await refsFile.exists()) { + if (await refsFile.exists() && refsFile.readAsStringSync() != '') { refsString = await refsFile.readAsString(); } List refs = jsonDecode(refsString); - refs.add([name, Uri.encodeFull(filePath)]); + Map ref = { + "name": node.name, + "path": Uri.encodeFull(filePath), + "kind": node.kindString + }; + + refs.add(ref); refsFile.writeAsString(json.encode(refs)); } @@ -156,6 +171,7 @@ Future createDoc(Node node, String childPath) async { title: ${node.name} description: ${node.comment?.shortText} reference: true +referenceKind: ${node.kindString ?? ''} --- '''; @@ -163,4 +179,15 @@ reference: true await file.writeAsString('\n \n', mode: FileMode.append); await file.writeAsString('# ${node.name} \n \n', mode: FileMode.append); + + final shortText = node.comment?.shortText; + final text = node.comment?.text; + // final tags = node.comment?.tags; + + if (shortText != null) { + await file.writeAsString('$shortText \n \n', mode: FileMode.append); + } + if (text != null) { + await file.writeAsString('$text \n \n', mode: FileMode.append); + } } From ecda8a44c359700c15812941d1be84c3ede3b79c Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Tue, 29 Mar 2022 16:33:28 +0100 Subject: [PATCH 09/41] chore: handle references on api layer --- api/src/utils/bundle.ts | 11 ++++++++++- api/src/utils/github.ts | 22 +++++++++++++++++++++- website/app/routes/$owner.$repo.$.tsx | 5 ++--- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/api/src/utils/bundle.ts b/api/src/utils/bundle.ts index a8cf247b..2dbfe49e 100644 --- a/api/src/utils/bundle.ts +++ b/api/src/utils/bundle.ts @@ -33,6 +33,12 @@ type BundleConstructorParams = { config?: OutputConfig; }; +export type References = { + name: string, + path: string, + kind: string +}[] + export class Bundle { code: string; markdown: string; @@ -48,6 +54,7 @@ export class Bundle { headerDepth: number; built: boolean; contentFetched: boolean; + referenceConfig: References | null constructor({ owner, @@ -77,6 +84,7 @@ export class Bundle { this.sourceChecked = false; this.built = false; this.contentFetched = false; + this.referenceConfig = null; } // check for branch/PR ref @@ -112,7 +120,7 @@ export class Bundle { this.markdown = githubContents.md; this.baseBranch = githubContents.baseBranch; this.repositoryFound = githubContents.repositoryFound; - + this.referenceConfig = githubContents.referenceConfig; this.formatConfigLocales(githubContents.config); await this.matchSymLinks(); this.contentFetched = true; @@ -156,6 +164,7 @@ export class Bundle { repositoryFound: this.repositoryFound, source: this.source, ref: this.ref, + referenceConfig: this.referenceConfig }; } diff --git a/api/src/utils/github.ts b/api/src/utils/github.ts index 75d51256..837a1f7f 100644 --- a/api/src/utils/github.ts +++ b/api/src/utils/github.ts @@ -1,6 +1,7 @@ import A2A from 'a2a'; import { graphql } from '@octokit/graphql'; import dotenv from 'dotenv'; +import { References } from './bundle'; dotenv.config(); const getGitHubToken = (() => { @@ -55,6 +56,9 @@ type PageContentsQuery = { mdxIndex?: { text: string; }; + referenceConfig?: { + text: string; + } }; }; @@ -69,6 +73,7 @@ export type Contents = { md: string | null; path: string; repositoryFound: boolean; + referenceConfig: References | null }; export async function getGitHubContents(metadata: MetaData, noDir?: boolean): Promise { @@ -78,7 +83,7 @@ export async function getGitHubContents(metadata: MetaData, noDir?: boolean): Pr const [error, response] = await A2A( getGithubGQLClient()({ query: ` - query RepositoryConfig($owner: String!, $repository: String!, $configJson: String!, $configYaml: String!, $configToml: String!, $mdx: String!, $mdxIndex: String!) { + query RepositoryConfig($owner: String!, $repository: String!, $configJson: String!, $configYaml: String!, $configToml: String!, $mdx: String!, $mdxIndex: String!, $referenceConfig: String!) { repository(owner: $owner, name: $repository) { baseBranch: defaultBranchRef { name @@ -109,6 +114,11 @@ export async function getGitHubContents(metadata: MetaData, noDir?: boolean): Pr text } } + references: object(expression: $referenceConfig) { + ... on Blob { + text + } + } } } `, @@ -119,6 +129,7 @@ export async function getGitHubContents(metadata: MetaData, noDir?: boolean): Pr configToml: `${metadata.ref}:docs.toml`, mdx: `${metadata.ref}:${absolutePath}.mdx`, mdxIndex: `${metadata.ref}:${indexPath}.mdx`, + referenceConfig: `${metadata.ref}:docs.ref.json` }), ); @@ -130,6 +141,14 @@ export async function getGitHubContents(metadata: MetaData, noDir?: boolean): Pr }; } + let referenceConfig = null; + try { + referenceConfig = response?.repository.referenceConfig?.text ? JSON.parse(response?.repository.referenceConfig?.text) : null + } catch (e) { + console.error('Could not parse reference config') + console.error(e); + } + return { repositoryFound: true, isFork: response?.repository?.isFork ?? false, @@ -141,6 +160,7 @@ export async function getGitHubContents(metadata: MetaData, noDir?: boolean): Pr }, md: response?.repository.mdxIndex?.text || response?.repository.mdx?.text || null, path: response?.repository.mdxIndex?.text ? indexPath : absolutePath, + referenceConfig }; } diff --git a/website/app/routes/$owner.$repo.$.tsx b/website/app/routes/$owner.$repo.$.tsx index 331a0540..ded4d26e 100644 --- a/website/app/routes/$owner.$repo.$.tsx +++ b/website/app/routes/$owner.$repo.$.tsx @@ -47,9 +47,8 @@ export const meta: MetaFunction = (props: { data?: DocumentationLoader }) => { return { 'twitter:card': 'summary_large_image', 'twiter:image:alt': props.data?.config?.name ?? '', - 'og:url': `https://docs.page/${props.data.owner}/${props.data.repo}${ - props.data.path ? `/${props.data.path}` : '' - }`, + 'og:url': `https://docs.page/${props.data.owner}/${props.data.repo}${props.data.path ? `/${props.data.path}` : '' + }`, 'og:site_name': 'docs.page', 'og:title': props.data.frontmatter?.title ?? props.data?.config?.name ?? props.data.repo ?? 'docs.page', From be1ad0c4325b5b4e225653c9444d07d74be71d58 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Tue, 29 Mar 2022 16:52:50 +0100 Subject: [PATCH 10/41] chore: started UI work --- packages/server/src/types.ts | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/packages/server/src/types.ts b/packages/server/src/types.ts index 85f9a693..cebc8cc4 100644 --- a/packages/server/src/types.ts +++ b/packages/server/src/types.ts @@ -36,6 +36,8 @@ export interface ConfigWithoutLocales { experimentalCodehike: boolean; // Whether Math is enabled experimentalMath: boolean; + // alias for references (root of path for references) + reference?: string; } export interface ConfigWithLocales { @@ -77,6 +79,8 @@ export interface ConfigWithLocales { experimentalCodehike: boolean; // Whether Math is enabled experimentalMath: boolean; + // alias for references (root of path for references) + reference?: string; } export type InputConfig = ConfigWithoutLocales | ConfigWithLocales; @@ -125,6 +129,8 @@ export interface OutputConfig { experimentalCodehike: boolean; // Whether Math is enabled experimentalMath: boolean; + // alias for references (root of path for references) + reference?: string; } export const defaultConfig: OutputConfig = { @@ -189,6 +195,13 @@ export type BundleSuccess = { repository: string; ref: string; }; + referenceConfig: References; }; +export type References = { + name: string, + path: string, + kind: string +}[] + export type BundleResponseData = BundleSuccess | BundleError; From 2ccbce40aff7011c3dfac4e573645429b7dc2e01 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Wed, 30 Mar 2022 10:42:13 +0100 Subject: [PATCH 11/41] feat: add references to frontend --- .prettierignore | 4 +- api/src/utils/bundle.ts | 12 +-- api/src/utils/github.ts | 16 +-- packages/server/src/types.ts | 8 +- website/app/components/DocsRefSwitch.tsx | 48 +++++++++ website/app/components/Sidebar.tsx | 105 +++++++++++++------- website/app/context.tsx | 4 + website/app/loaders/documentation.server.ts | 9 ++ website/app/routes/$owner.$repo.$.tsx | 5 +- website/app/utils/config.ts | 4 + 10 files changed, 159 insertions(+), 56 deletions(-) create mode 100644 website/app/components/DocsRefSwitch.tsx diff --git a/.prettierignore b/.prettierignore index a927018b..66731ef0 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,4 +5,6 @@ dist repositories.json domains.json spelling.json -_docs.page \ No newline at end of file +_docs.page +packages/dart_cli/example +packages/dart_cli/docs \ No newline at end of file diff --git a/api/src/utils/bundle.ts b/api/src/utils/bundle.ts index 2dbfe49e..cb566bfa 100644 --- a/api/src/utils/bundle.ts +++ b/api/src/utils/bundle.ts @@ -34,10 +34,10 @@ type BundleConstructorParams = { }; export type References = { - name: string, - path: string, - kind: string -}[] + name: string; + path: string; + kind: string; +}[]; export class Bundle { code: string; @@ -54,7 +54,7 @@ export class Bundle { headerDepth: number; built: boolean; contentFetched: boolean; - referenceConfig: References | null + referenceConfig: References | null; constructor({ owner, @@ -164,7 +164,7 @@ export class Bundle { repositoryFound: this.repositoryFound, source: this.source, ref: this.ref, - referenceConfig: this.referenceConfig + referenceConfig: this.referenceConfig, }; } diff --git a/api/src/utils/github.ts b/api/src/utils/github.ts index 837a1f7f..420c5406 100644 --- a/api/src/utils/github.ts +++ b/api/src/utils/github.ts @@ -58,7 +58,7 @@ type PageContentsQuery = { }; referenceConfig?: { text: string; - } + }; }; }; @@ -73,7 +73,7 @@ export type Contents = { md: string | null; path: string; repositoryFound: boolean; - referenceConfig: References | null + referenceConfig: References | null; }; export async function getGitHubContents(metadata: MetaData, noDir?: boolean): Promise { @@ -114,7 +114,7 @@ export async function getGitHubContents(metadata: MetaData, noDir?: boolean): Pr text } } - references: object(expression: $referenceConfig) { + referenceConfig: object(expression: $referenceConfig) { ... on Blob { text } @@ -129,7 +129,7 @@ export async function getGitHubContents(metadata: MetaData, noDir?: boolean): Pr configToml: `${metadata.ref}:docs.toml`, mdx: `${metadata.ref}:${absolutePath}.mdx`, mdxIndex: `${metadata.ref}:${indexPath}.mdx`, - referenceConfig: `${metadata.ref}:docs.ref.json` + referenceConfig: `${metadata.ref}:docs.refs.json`, }), ); @@ -143,9 +143,11 @@ export async function getGitHubContents(metadata: MetaData, noDir?: boolean): Pr let referenceConfig = null; try { - referenceConfig = response?.repository.referenceConfig?.text ? JSON.parse(response?.repository.referenceConfig?.text) : null + referenceConfig = response?.repository.referenceConfig?.text + ? JSON.parse(response?.repository.referenceConfig?.text) + : null; } catch (e) { - console.error('Could not parse reference config') + console.error('Could not parse reference config'); console.error(e); } @@ -160,7 +162,7 @@ export async function getGitHubContents(metadata: MetaData, noDir?: boolean): Pr }, md: response?.repository.mdxIndex?.text || response?.repository.mdx?.text || null, path: response?.repository.mdxIndex?.text ? indexPath : absolutePath, - referenceConfig + referenceConfig, }; } diff --git a/packages/server/src/types.ts b/packages/server/src/types.ts index cebc8cc4..f019a5e2 100644 --- a/packages/server/src/types.ts +++ b/packages/server/src/types.ts @@ -199,9 +199,9 @@ export type BundleSuccess = { }; export type References = { - name: string, - path: string, - kind: string -}[] + name: string; + path: string; + kind: string; +}[]; export type BundleResponseData = BundleSuccess | BundleError; diff --git a/website/app/components/DocsRefSwitch.tsx b/website/app/components/DocsRefSwitch.tsx new file mode 100644 index 00000000..6467e09a --- /dev/null +++ b/website/app/components/DocsRefSwitch.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import { useNavigate } from 'react-router-dom'; +import { useBaseUrl } from '~/context'; + +/** + * Renders a switch which toggles locale + */ + +export function DocsRefsSwitch({ + isReference, + referencePath, +}: { + isReference: boolean; + referencePath: string; +}) { + const navigate = useNavigate(); + const baseUrl = useBaseUrl(); + + const onChange = (value: string) => { + navigate(value === 'DOCS' ? baseUrl : referencePath, { replace: true }); + }; + + const container = (children?: React.ReactElement) => ( +
+ {children} +
+ ); + + return container( + <> + + , + ); +} diff --git a/website/app/components/Sidebar.tsx b/website/app/components/Sidebar.tsx index 58970347..61d018f4 100644 --- a/website/app/components/Sidebar.tsx +++ b/website/app/components/Sidebar.tsx @@ -3,12 +3,19 @@ import { useLocation } from 'react-router-dom'; import { useDocumentationContext } from '~/context'; import { DarkModeToggle } from './DarkModeToggle'; import { DocsLink } from './DocsLink'; +import { DocsRefsSwitch } from './DocsRefSwitch'; import { LocaleSelect } from './LocaleSelect'; export function Sidebar() { - const { sidebar, locales } = useDocumentationContext().config; + const documentationContext = useDocumentationContext(); + const { sidebar, locales, reference } = documentationContext.config; + const { referenceConfig, frontmatter } = documentationContext; + + const referencePath = reference ?? 'API'; + const location = useLocation(); const currentLocale = location.pathname.split('/')[3]; + return ( ); diff --git a/website/app/context.tsx b/website/app/context.tsx index 26022dad..896e9d6c 100644 --- a/website/app/context.tsx +++ b/website/app/context.tsx @@ -38,6 +38,7 @@ export function useDocumentationContext() { export function useBaseUrl(): string { const previewMode = usePreviewMode(); const { domain } = useCustomDomain(); + const { owner, repo } = React.useContext(DocumentationContext); if (previewMode.enabled) { return '#/'; @@ -47,6 +48,9 @@ export function useBaseUrl(): string { let url = '/'; + if (!domain) { + url += `${owner}/${repo}`; + } if (ref && !domain) { url += `${ref === 'HEAD' ? '' : `~${ref}`}`; } diff --git a/website/app/loaders/documentation.server.ts b/website/app/loaders/documentation.server.ts index e9cb954a..6220a9ab 100644 --- a/website/app/loaders/documentation.server.ts +++ b/website/app/loaders/documentation.server.ts @@ -46,6 +46,14 @@ export type DocumentationLoader = { frontmatter: BundleSuccess['frontmatter']; // base branch baseBranch: string; + // + referenceConfig?: + | { + name: string; + kind: string; + path: string; + }[] + | null; }; // Utility to guard against a bundler error. @@ -118,6 +126,7 @@ export const docsLoader: LoaderFunction = async ({ params }) => { config: mergeConfig(response.config), frontmatter: response.frontmatter, baseBranch: response.baseBranch ?? 'main', + referenceConfig: response.referenceConfig, }, { headers: { diff --git a/website/app/routes/$owner.$repo.$.tsx b/website/app/routes/$owner.$repo.$.tsx index ded4d26e..331a0540 100644 --- a/website/app/routes/$owner.$repo.$.tsx +++ b/website/app/routes/$owner.$repo.$.tsx @@ -47,8 +47,9 @@ export const meta: MetaFunction = (props: { data?: DocumentationLoader }) => { return { 'twitter:card': 'summary_large_image', 'twiter:image:alt': props.data?.config?.name ?? '', - 'og:url': `https://docs.page/${props.data.owner}/${props.data.repo}${props.data.path ? `/${props.data.path}` : '' - }`, + 'og:url': `https://docs.page/${props.data.owner}/${props.data.repo}${ + props.data.path ? `/${props.data.path}` : '' + }`, 'og:site_name': 'docs.page', 'og:title': props.data.frontmatter?.title ?? props.data?.config?.name ?? props.data.repo ?? 'docs.page', diff --git a/website/app/utils/config.ts b/website/app/utils/config.ts index d20aceec..cd91d416 100644 --- a/website/app/utils/config.ts +++ b/website/app/utils/config.ts @@ -98,6 +98,8 @@ export interface ProjectConfig { experimentalCodehike: boolean; // Whether Math is enabled experimentalMath: boolean; + // Whether Math is enabled + reference: string; } export const defaultConfig: ProjectConfig = { @@ -117,6 +119,7 @@ export const defaultConfig: ProjectConfig = { zoomImages: false, experimentalCodehike: false, experimentalMath: false, + reference: 'API', }; // Merges any user config with default values. @@ -151,6 +154,7 @@ export function mergeConfig(json: Record): ProjectConfig { defaultConfig.experimentalCodehike, ), experimentalMath: getBoolean(json, 'experimentalMath', defaultConfig.experimentalMath), + reference: getString(json, 'reference', defaultConfig.reference), }; } From 784337169a6da94d10d82d3edb2667295abd2e96 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Wed, 30 Mar 2022 13:34:06 +0100 Subject: [PATCH 12/41] chore: fix handling of references in config --- packages/dart_cli/example/main.dart | 2 - website/app/components/DocsRefSwitch.tsx | 54 +++++++++++++----------- website/app/components/Sidebar.tsx | 6 +-- website/app/utils/config.ts | 6 +-- 4 files changed, 35 insertions(+), 33 deletions(-) diff --git a/packages/dart_cli/example/main.dart b/packages/dart_cli/example/main.dart index f070ad11..117b72c8 100644 --- a/packages/dart_cli/example/main.dart +++ b/packages/dart_cli/example/main.dart @@ -1,5 +1,3 @@ -import 'dart:io'; - import 'package:docs_page/src/typedoc.dart'; void main() async { diff --git a/website/app/components/DocsRefSwitch.tsx b/website/app/components/DocsRefSwitch.tsx index 6467e09a..027d1819 100644 --- a/website/app/components/DocsRefSwitch.tsx +++ b/website/app/components/DocsRefSwitch.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import { useNavigate } from 'react-router-dom'; -import { useBaseUrl } from '~/context'; +import { DocsLink } from './DocsLink'; +import cx from 'classnames'; /** * Renders a switch which toggles locale @@ -13,36 +13,40 @@ export function DocsRefsSwitch({ isReference: boolean; referencePath: string; }) { - const navigate = useNavigate(); - const baseUrl = useBaseUrl(); - - const onChange = (value: string) => { - navigate(value === 'DOCS' ? baseUrl : referencePath, { replace: true }); - }; - const container = (children?: React.ReactElement) => ( -
+
{children}
); return container( - <> - - , + + + , ); } diff --git a/website/app/components/Sidebar.tsx b/website/app/components/Sidebar.tsx index 61d018f4..1e0226d5 100644 --- a/website/app/components/Sidebar.tsx +++ b/website/app/components/Sidebar.tsx @@ -8,11 +8,11 @@ import { LocaleSelect } from './LocaleSelect'; export function Sidebar() { const documentationContext = useDocumentationContext(); - const { sidebar, locales, reference } = documentationContext.config; + const { sidebar, locales, references } = documentationContext.config; const { referenceConfig, frontmatter } = documentationContext; - const referencePath = reference ?? 'API'; - + const referencePath = references ?? 'API'; + console.log('boop', references); const location = useLocation(); const currentLocale = location.pathname.split('/')[3]; diff --git a/website/app/utils/config.ts b/website/app/utils/config.ts index cd91d416..33b1808e 100644 --- a/website/app/utils/config.ts +++ b/website/app/utils/config.ts @@ -99,7 +99,7 @@ export interface ProjectConfig { // Whether Math is enabled experimentalMath: boolean; // Whether Math is enabled - reference: string; + references: string; } export const defaultConfig: ProjectConfig = { @@ -119,7 +119,7 @@ export const defaultConfig: ProjectConfig = { zoomImages: false, experimentalCodehike: false, experimentalMath: false, - reference: 'API', + references: 'API', }; // Merges any user config with default values. @@ -154,7 +154,7 @@ export function mergeConfig(json: Record): ProjectConfig { defaultConfig.experimentalCodehike, ), experimentalMath: getBoolean(json, 'experimentalMath', defaultConfig.experimentalMath), - reference: getString(json, 'reference', defaultConfig.reference), + references: getString(json, 'references', defaultConfig.references), }; } From eb139ef7ed344fa52c2e8d72a402c81a91e7a883 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Wed, 30 Mar 2022 14:03:24 +0100 Subject: [PATCH 13/41] feat: generate overview page --- packages/dart_cli/lib/src/typedoc.dart | 80 ++++++++++++++++++-------- 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/packages/dart_cli/lib/src/typedoc.dart b/packages/dart_cli/lib/src/typedoc.dart index 13ef344c..32031391 100644 --- a/packages/dart_cli/lib/src/typedoc.dart +++ b/packages/dart_cli/lib/src/typedoc.dart @@ -134,14 +134,32 @@ Future generate( final refPath = path.relative(path.joinAll([currentPath, child.name]), from: path.joinAll([Directory.current.path, 'docs'])); - await addRef(child, refPath); + await addRef(node: child, filePath: refPath); - await createDoc(child, childPath); + await createDoc(node: child, filePath: childPath); } } + await addRef( + name: 'Overview', filePath: path.joinAll([currentPath, 'index.mdx'])); + + await createDoc( + name: 'Overview', filePath: path.joinAll([currentPath, 'index.mdx'])); } -Future addRef(Node node, String filePath) async { +Future addRef( + {Node? node, String? name, required String filePath}) async { + Map ref; + if (node != null) { + ref = { + "name": node.name, + "path": Uri.encodeFull(filePath), + "kind": node.kindString + }; + } else if (name != null) { + ref = {"name": name, "path": Uri.encodeFull(filePath), "kind": "Overview"}; + } else { + throw Exception('need to specify node or name'); + } File refsFile = File(path.joinAll([Directory.current.path, 'docs.refs.json'])); @@ -153,20 +171,17 @@ Future addRef(Node node, String filePath) async { List refs = jsonDecode(refsString); - Map ref = { - "name": node.name, - "path": Uri.encodeFull(filePath), - "kind": node.kindString - }; - refs.add(ref); refsFile.writeAsString(json.encode(refs)); } -Future createDoc(Node node, String childPath) async { - File file = await File(childPath).create(recursive: true); - String frontmatter = ''' +Future createDoc( + {Node? node, String? name, required String filePath}) async { + File file = await File(filePath).create(recursive: true); + String frontmatter; + if (node != null) { + frontmatter = ''' --- title: ${node.name} description: ${node.comment?.shortText} @@ -175,19 +190,38 @@ referenceKind: ${node.kindString ?? ''} --- '''; - await file.writeAsString(frontmatter); - await file.writeAsString('\n \n', mode: FileMode.append); + await file.writeAsString(frontmatter); + await file.writeAsString('\n \n', mode: FileMode.append); - await file.writeAsString('# ${node.name} \n \n', mode: FileMode.append); + await file.writeAsString('# ${node.name} \n \n', mode: FileMode.append); - final shortText = node.comment?.shortText; - final text = node.comment?.text; - // final tags = node.comment?.tags; + final shortText = node.comment?.shortText; + final text = node.comment?.text; + // final tags = node.comment?.tags; - if (shortText != null) { - await file.writeAsString('$shortText \n \n', mode: FileMode.append); - } - if (text != null) { - await file.writeAsString('$text \n \n', mode: FileMode.append); + if (shortText != null) { + await file.writeAsString('$shortText \n \n', mode: FileMode.append); + } + if (text != null) { + await file.writeAsString('$text \n \n', mode: FileMode.append); + } + } else if (name != null) { + frontmatter = ''' +--- +title: $name +description: Overview for references +reference: true +referenceKind: null +--- +'''; + await file.writeAsString(frontmatter); + await file.writeAsString('\n \n', mode: FileMode.append); + + await file.writeAsString('# $name \n \n', mode: FileMode.append); + + await file.writeAsString('# Overview for API references', + mode: FileMode.append); + } else { + throw Exception('Must provide node or name'); } } From d20eb93d464123934aa62437bff61adf1e5acf79 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Wed, 30 Mar 2022 14:47:52 +0100 Subject: [PATCH 14/41] chore: refactor createIndexFile out --- packages/dart_cli/lib/src/typedoc.dart | 58 +++++++++++++------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/packages/dart_cli/lib/src/typedoc.dart b/packages/dart_cli/lib/src/typedoc.dart index 32031391..0a79bfa9 100644 --- a/packages/dart_cli/lib/src/typedoc.dart +++ b/packages/dart_cli/lib/src/typedoc.dart @@ -142,8 +142,7 @@ Future generate( await addRef( name: 'Overview', filePath: path.joinAll([currentPath, 'index.mdx'])); - await createDoc( - name: 'Overview', filePath: path.joinAll([currentPath, 'index.mdx'])); + await createIndexFile(filePath: path.joinAll([currentPath, 'index.mdx'])); } Future addRef( @@ -176,12 +175,9 @@ Future addRef( refsFile.writeAsString(json.encode(refs)); } -Future createDoc( - {Node? node, String? name, required String filePath}) async { +Future createDoc({required Node node, required String filePath}) async { File file = await File(filePath).create(recursive: true); - String frontmatter; - if (node != null) { - frontmatter = ''' + String frontmatter = ''' --- title: ${node.name} description: ${node.comment?.shortText} @@ -190,38 +186,40 @@ referenceKind: ${node.kindString ?? ''} --- '''; - await file.writeAsString(frontmatter); - await file.writeAsString('\n \n', mode: FileMode.append); + await file.writeAsString(frontmatter); + await file.writeAsString('\n \n', mode: FileMode.append); - await file.writeAsString('# ${node.name} \n \n', mode: FileMode.append); + await file.writeAsString('# ${node.name} \n \n', mode: FileMode.append); - final shortText = node.comment?.shortText; - final text = node.comment?.text; - // final tags = node.comment?.tags; + final shortText = node.comment?.shortText; + final text = node.comment?.text; + // final tags = node.comment?.tags; - if (shortText != null) { - await file.writeAsString('$shortText \n \n', mode: FileMode.append); - } - if (text != null) { - await file.writeAsString('$text \n \n', mode: FileMode.append); - } - } else if (name != null) { - frontmatter = ''' + if (shortText != null) { + await file.writeAsString('$shortText \n \n', mode: FileMode.append); + } + if (text != null) { + await file.writeAsString('$text \n \n', mode: FileMode.append); + } +} + +Future createIndexFile({required String filePath}) async { + File file = await File(filePath).create(recursive: true); + + String frontmatter = ''' --- -title: $name +title: Overview description: Overview for references reference: true referenceKind: null --- '''; - await file.writeAsString(frontmatter); - await file.writeAsString('\n \n', mode: FileMode.append); - await file.writeAsString('# $name \n \n', mode: FileMode.append); + await file.writeAsString(frontmatter); + await file.writeAsString('\n \n', mode: FileMode.append); - await file.writeAsString('# Overview for API references', - mode: FileMode.append); - } else { - throw Exception('Must provide node or name'); - } + await file.writeAsString('# References \n \n', mode: FileMode.append); + + await file.writeAsString('# Overview for API references', + mode: FileMode.append); } From 465e9e42b864b7aa9e0cf2b26bd06eee44c535b4 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Wed, 30 Mar 2022 15:56:51 +0100 Subject: [PATCH 15/41] chore: update generator --- packages/dart_cli/lib/src/typedoc.dart | 74 ++++++++++++++++++++------ 1 file changed, 59 insertions(+), 15 deletions(-) diff --git a/packages/dart_cli/lib/src/typedoc.dart b/packages/dart_cli/lib/src/typedoc.dart index 0a79bfa9..b6e3c68b 100644 --- a/packages/dart_cli/lib/src/typedoc.dart +++ b/packages/dart_cli/lib/src/typedoc.dart @@ -1,3 +1,5 @@ +import 'dart:ffi'; + import 'package:docs_page/src/docs_page_config.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:path/path.dart' as path; @@ -93,7 +95,6 @@ class Tag { /// Connect the generated [_$TagToJson] function to the `toJson` method. Map toJson() => _$TagToJson(this); } -// get the typedoc.json from the repo Future getJson() async { final current = Directory.current; @@ -109,8 +110,6 @@ Future getJson() async { return parsed; } -// parse it - Future generate( {required Node ast, String? docPath, List? refs}) async { DocsPageConfig config = DocsPageConfig.fromDirectory(); @@ -175,9 +174,14 @@ Future addRef( refsFile.writeAsString(json.encode(refs)); } -Future createDoc({required Node node, required String filePath}) async { +Future createDoc( + {required Node node, + required String filePath, + bool frontmatterEnabled = true, + int depth = 1}) async { File file = await File(filePath).create(recursive: true); - String frontmatter = ''' + if (frontmatterEnabled) { + String frontmatter = ''' --- title: ${node.name} description: ${node.comment?.shortText} @@ -186,20 +190,60 @@ referenceKind: ${node.kindString ?? ''} --- '''; - await file.writeAsString(frontmatter); - await file.writeAsString('\n \n', mode: FileMode.append); + await file.writeAsString(frontmatter); + } + + String headerPrefix = ''; + + for (int i = 0; i < depth; i++) { + headerPrefix += '#'; + } + await appendAllToFile(file, [ + '$headerPrefix ${node.name}', + node.comment?.shortText, + node.comment?.text, + ]); - await file.writeAsString('# ${node.name} \n \n', mode: FileMode.append); + List? children = node.children; - final shortText = node.comment?.shortText; - final text = node.comment?.text; - // final tags = node.comment?.tags; + if (children != null) { + for (final child in children) { + await createDoc( + node: child, + filePath: filePath, + frontmatterEnabled: false, + depth: depth + 1); + } + } - if (shortText != null) { - await file.writeAsString('$shortText \n \n', mode: FileMode.append); + List? sources = node.sources; + + if (sources != null) { + await appendToFile(file, '**Source(s)**'); + for (final source in sources) { + String fileName = source.fileName; + String character = source.character.toString(); + String line = source.line.toString(); + + await appendAllToFile(file, [ + 'fileName: $fileName', + 'Character: $character', + 'line: $line', + '---' + ]); + } } - if (text != null) { - await file.writeAsString('$text \n \n', mode: FileMode.append); +} + +Future appendToFile(File file, String? content) async { + if (content != null) { + await file.writeAsString(content + '\n \n ', mode: FileMode.append); + } +} + +Future appendAllToFile(File file, List content) async { + for (final text in content) { + await appendToFile(file, text); } } From c03042724156823b0780f1aee5268f93d200a592 Mon Sep 17 00:00:00 2001 From: Jacob Cable Date: Thu, 31 Mar 2022 11:21:02 +0100 Subject: [PATCH 16/41] feat: categorize sidebar by kind --- packages/dart_cli/bin/docs_page.dart | 2 +- .../dart_cli/lib/src/docs_page_config.dart | 4 +- .../dart_cli/lib/src/docs_page_config.g.dart | 2 + packages/dart_cli/lib/src/typedoc.dart | 51 ++++++++------ website/app/components/DocsRefSwitch.tsx | 69 ++++++++++--------- website/app/components/Sidebar.tsx | 51 ++++++++++---- website/app/components/mdx/GithubLink.tsx | 8 +++ website/app/components/mdx/index.tsx | 2 + 8 files changed, 117 insertions(+), 72 deletions(-) create mode 100644 website/app/components/mdx/GithubLink.tsx diff --git a/packages/dart_cli/bin/docs_page.dart b/packages/dart_cli/bin/docs_page.dart index 23a05c8a..c4f2c35b 100644 --- a/packages/dart_cli/bin/docs_page.dart +++ b/packages/dart_cli/bin/docs_page.dart @@ -13,7 +13,7 @@ void main(List arguments) async { await createFiles(); break; case 'typedoc': - Node ast = await getJson(); + Node ast = await getTypedocJson(); await generate(ast: ast); break; diff --git a/packages/dart_cli/lib/src/docs_page_config.dart b/packages/dart_cli/lib/src/docs_page_config.dart index 01c95087..009b3923 100644 --- a/packages/dart_cli/lib/src/docs_page_config.dart +++ b/packages/dart_cli/lib/src/docs_page_config.dart @@ -18,6 +18,7 @@ class DocsPageConfig { final bool? experimentalCodeHike; final bool? experimentalMath; final String? references; + final String? typedocEntryDir; DocsPageConfig( {this.name, @@ -28,7 +29,8 @@ class DocsPageConfig { this.googleTagManager, this.experimentalCodeHike, this.experimentalMath, - this.references}); + this.references, + this.typedocEntryDir}); factory DocsPageConfig.fromJson(Map json) => _$DocsPageConfigFromJson(json); diff --git a/packages/dart_cli/lib/src/docs_page_config.g.dart b/packages/dart_cli/lib/src/docs_page_config.g.dart index 194ef875..ab2d6676 100644 --- a/packages/dart_cli/lib/src/docs_page_config.g.dart +++ b/packages/dart_cli/lib/src/docs_page_config.g.dart @@ -20,6 +20,7 @@ DocsPageConfig _$DocsPageConfigFromJson(Map json) => experimentalCodeHike: json['experimentalCodeHike'] as bool?, experimentalMath: json['experimentalMath'] as bool?, references: json['references'] as String?, + typedocEntryDir: json['typedocEntryDir'] as String?, ); Map _$DocsPageConfigToJson(DocsPageConfig instance) => @@ -33,6 +34,7 @@ Map _$DocsPageConfigToJson(DocsPageConfig instance) => 'experimentalCodeHike': instance.experimentalCodeHike, 'experimentalMath': instance.experimentalMath, 'references': instance.references, + 'typedocEntryDir': instance.typedocEntryDir, }; DocSearch _$DocSearchFromJson(Map json) => DocSearch( diff --git a/packages/dart_cli/lib/src/typedoc.dart b/packages/dart_cli/lib/src/typedoc.dart index b6e3c68b..326d644d 100644 --- a/packages/dart_cli/lib/src/typedoc.dart +++ b/packages/dart_cli/lib/src/typedoc.dart @@ -1,10 +1,9 @@ -import 'dart:ffi'; - import 'package:docs_page/src/docs_page_config.dart'; import 'package:json_annotation/json_annotation.dart'; import 'package:path/path.dart' as path; import 'dart:io'; import 'dart:convert'; +import 'package:ansi_styles/extension.dart'; part 'typedoc.g.dart'; @@ -96,7 +95,7 @@ class Tag { Map toJson() => _$TagToJson(this); } -Future getJson() async { +Future getTypedocJson() async { final current = Directory.current; final jsonPath = path.joinAll([current.path, 'docs', 'typedoc.json']); @@ -127,6 +126,8 @@ Future generate( refsFile.delete(recursive: true); if (children != null && children.isNotEmpty) { + print('Docs.page created files:'.blueBright); + for (final child in children) { final childPath = path.joinAll([currentPath, '${child.name}.mdx']); @@ -136,6 +137,7 @@ Future generate( await addRef(node: child, filePath: refPath); await createDoc(node: child, filePath: childPath); + print(childPath.blue); } } await addRef( @@ -180,6 +182,7 @@ Future createDoc( bool frontmatterEnabled = true, int depth = 1}) async { File file = await File(filePath).create(recursive: true); + if (frontmatterEnabled) { String frontmatter = ''' --- @@ -204,6 +207,16 @@ referenceKind: ${node.kindString ?? ''} node.comment?.text, ]); + List? sources = node.sources; + + if (sources != null) { + await appendToFile(file, '**Source**'); + for (final source in sources) { + DocsPageConfig config = DocsPageConfig.fromDirectory(); + await appendToFile(file, getGithubLink(config: config, source: source)); + } + } + List? children = node.children; if (children != null) { @@ -215,24 +228,6 @@ referenceKind: ${node.kindString ?? ''} depth: depth + 1); } } - - List? sources = node.sources; - - if (sources != null) { - await appendToFile(file, '**Source(s)**'); - for (final source in sources) { - String fileName = source.fileName; - String character = source.character.toString(); - String line = source.line.toString(); - - await appendAllToFile(file, [ - 'fileName: $fileName', - 'Character: $character', - 'line: $line', - '---' - ]); - } - } } Future appendToFile(File file, String? content) async { @@ -267,3 +262,17 @@ referenceKind: null await file.writeAsString('# Overview for API references', mode: FileMode.append); } + +String getGithubLink({required DocsPageConfig config, required Source source}) { + final typedocEntryDir = config.typedocEntryDir; + + final fileName = source.fileName; + final line = source.line; + + if (typedocEntryDir != null) { + final filePath = path.joinAll([typedocEntryDir, fileName]); + return ''; + } else { + throw Exception('Missing typedocEntryDir option in docs.json'); + } +} diff --git a/website/app/components/DocsRefSwitch.tsx b/website/app/components/DocsRefSwitch.tsx index 027d1819..3c9b9924 100644 --- a/website/app/components/DocsRefSwitch.tsx +++ b/website/app/components/DocsRefSwitch.tsx @@ -1,10 +1,7 @@ import React from 'react'; import { DocsLink } from './DocsLink'; import cx from 'classnames'; - -/** - * Renders a switch which toggles locale - */ +import { AcademicCapIcon, ArchiveIcon } from '@heroicons/react/solid'; export function DocsRefsSwitch({ isReference, @@ -13,40 +10,44 @@ export function DocsRefsSwitch({ isReference: boolean; referencePath: string; }) { - const container = (children?: React.ReactElement) => ( -
- {children} -
- ); - - return container( + return (
  • - - cx('my-2 block', { - 'hover:text-gray-800 dark:hover:text-gray-100': isReference, - 'text-docs-theme border-docs-theme font-medium': !isReference, - }) - } - > - {'Docs'} - +
    +
    + +
    + + cx('my-2 block', { + 'hover:text-gray-800 dark:hover:text-gray-100': isReference, + 'text-docs-theme border-docs-theme font-medium': !isReference, + }) + } + > + {'Docs'} + +
  • - - cx('my-2 block', { - 'hover:text-gray-800 dark:hover:text-gray-100': !isReference, - 'text-docs-theme border-docs-theme font-medium': isReference, - }) - } - > - {referencePath} - +
    +
    + +
    + + cx('my-2 block', { + 'hover:text-gray-800 dark:hover:text-gray-100': !isReference, + 'text-docs-theme border-docs-theme font-medium': isReference, + }) + } + > + {referencePath} + +
  • -
, + ); } diff --git a/website/app/components/Sidebar.tsx b/website/app/components/Sidebar.tsx index 1e0226d5..dec59b9f 100644 --- a/website/app/components/Sidebar.tsx +++ b/website/app/components/Sidebar.tsx @@ -12,10 +12,21 @@ export function Sidebar() { const { referenceConfig, frontmatter } = documentationContext; const referencePath = references ?? 'API'; - console.log('boop', references); const location = useLocation(); const currentLocale = location.pathname.split('/')[3]; + const formattedRefs: Record = {}; + + for (const ref of referenceConfig || []) { + if (!formattedRefs[ref.kind]) { + formattedRefs[ref.kind] = [ref]; + } else { + formattedRefs[ref.kind].push(ref); + } + } + + const formattedRefsArray = Object.entries(formattedRefs); + return (