Skip to content

Commit

Permalink
Proof of concept files
Browse files Browse the repository at this point in the history
  • Loading branch information
diegoaltb committed May 15, 2022
1 parent 9fc098e commit 38c2f0a
Show file tree
Hide file tree
Showing 8 changed files with 578 additions and 0 deletions.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Files and directories created by pub.
.dart_tool/
.packages
# Conventional directory for build output.
build/
# Extra files
.idea
doc
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 0.0.1

- Initial version.
30 changes: 30 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.

include: package:lints/recommended.yaml

# Uncomment the following section to specify additional rules.

# linter:
# rules:
# - camel_case_types

# analyzer:
# exclude:
# - path/to/excluded/files/**

# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints

# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options
16 changes: 16 additions & 0 deletions bin/fsgen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import 'package:dartdoc/options.dart';
import 'package:fsgen/fsgen.dart' as fsgen;
import 'package:dartdoc/dartdoc.dart';

Future<void> main(List<String> arguments) async {
var config = parseOptions(pubPackageMetaProvider, arguments);
if (config == null) {
return;
}
final packageConfigProvider = PhysicalPackageConfigProvider();
final packageBuilder =
PubPackageBuilder(config, pubPackageMetaProvider, packageConfigProvider);
final dartdoc = Dartdoc.withEmptyGenerator(config, packageBuilder);
dartdoc.generator = fsgen.FsGenerator();
dartdoc.executeGuarded();
}
129 changes: 129 additions & 0 deletions lib/fsgen.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import 'package:dartdoc/dartdoc.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/src/dart/element/element.dart';

class Dependency {
final Uri libraryUri;
final String libraryName;
final String libraryVersion;

Dependency(this.libraryUri, this.libraryName, this.libraryVersion);

@override
bool operator ==(Object other) =>
other is Dependency &&
(libraryUri == other.libraryUri &&
libraryName == other.libraryName &&
libraryVersion == other.libraryVersion);

@override
int get hashCode => Object.hash(libraryUri, libraryName, libraryVersion);

@override
String toString() {
return 'Dependency{libraryUri: $libraryUri, libraryName: $libraryName, libraryVersion: $libraryVersion}';
}
}

class FsGenerator implements Generator {
Dependency? dependency(
LibraryElement? elementType, PackageGraph packageGraph) {
if (elementType == null) return null;
final metadata = packageGraph.packageMetaProvider
.fromElement(elementType, packageGraph.config.sdkDir);
return Dependency(elementType.source.uri, metadata!.name, metadata.version);
}

String extractNamedParams(Iterable<ParameterElement> parameters) {
var positionalUntil = -1;
for (final p in parameters) {
positionalUntil += 1;
if (p.isNamed) {
break;
}
}
return positionalUntil != -1 && positionalUntil != parameters.length - 1? '[<NamedParams${positionalUntil != 0 ? '(fromIndex=$positionalUntil)' : ''}>] ' : '';
}
String renderParams(Iterable<ParameterElement> parameters) {
return '(${parameters.isEmpty ? '' : parameters.map((e) => '${e.isRequiredNamed || e.isRequiredPositional ? '' : '?'}${e.name} : ${e is TypeParameterElementType ? "'":''}${e.type.element?.name ?? e.type.alias?.element.name ?? e.type.getDisplayString(withNullability: true)}').reduce((value, element) => '$value, $element')})';
}

String renderGenericArgs(Iterable<Element> genericParams) => genericParams
.isEmpty
? ''
: '<${genericParams.map((e) => "${e.kind == ElementKind.TYPE_PARAMETER ? "'":''}${e.name}").reduce((value, element) => '$value, $element')}>';

@override
Future<void> generate(PackageGraph packageGraph, FileWriter writer) async {
for (final package in packageGraph.packages) {
var buffer = StringBuffer();

for (final lib in package.libraries) {
if (!lib.isPublic) continue;
buffer.writeln('module rec ``${lib.name}``=');
final currentLibUri = lib.element.source.uri;
final dependencies = Set<Dependency>.identity();
for (final libEl in lib.element.importedLibraries) {
if (libEl.isPrivate) continue;
final dep = dependency(libEl, packageGraph);
if (dep != null && dep.libraryUri != currentLibUri) {
dependencies.add(dep);
}
}
for (final clazz in lib.classes) {
if (!clazz.isCanonical) continue;
final genericParams = clazz.typeParameters;
final renderedClassGenerics =
renderGenericArgs(genericParams.map((e) => e.element!));
var headerPrinted = false;
var moreThanHeader = false;
var defaultConstructor = clazz.unnamedConstructor;
final superClazz = (clazz.supertype?.isPublic ?? false) ? clazz.supertype : null;
final superGenerics = renderGenericArgs(
superClazz?.typeArguments.where((e) => e.type.element != null)
.map((e) => e.type.element!) ?? []);
buffer.writeln(' [<ImportMember("$currentLibUri")>');
if (defaultConstructor != null) {
headerPrinted = true;
final renderedParams = renderParams(defaultConstructor.parameters.map((e) => e.element!));
buffer.writeln(
' type ${clazz.name}$renderedClassGenerics ${extractNamedParams(defaultConstructor.parameters.map((e) => e.element!))} $renderedParams =');
}
if (superClazz != null) {
moreThanHeader = true;
final args = ((defaultConstructor?.element as ConstructorElementImpl?)?.superConstructor?.parameters.length ?? 0);
buffer.writeln(' inherit ${superClazz.name}$superGenerics(${args == 0 ? '' : List.generate(args, (_) => 'jsNative')
.reduce((value, element) => '$value, $element')})');
}

if (!headerPrinted) {
headerPrinted = true;
buffer.writeln(' type ${clazz.name}$renderedClassGenerics =');
}
for (final constructor in clazz.constructors
.where((element) => !element.isUnnamedConstructor)) {
if (!constructor.isCanonical) continue;
final renderedParams = renderParams(constructor.parameters.map((e) => e.element!));
moreThanHeader = true;
final treated = constructor.name.substring(clazz.name.length + 1);
buffer.writeln(
' ${extractNamedParams(constructor.parameters.map((e) => e.element!))}${treated != 'new' ? 'static member' : ''} $treated$renderedParams : ${clazz.name}$renderedClassGenerics = jsNative');
//print('SDK? ${lib.isInSdk} - $package - ${package.packageMeta.version} - ${lib.element.source.uri} - $lib - $clazz - ${clazz.supertype ?? 'No super'} - $constructor');
}

if (!moreThanHeader) {
buffer.writeln(' class end');
}
buffer.writeln();
}

writer.write('${lib.hashCode}.fs', buffer.toString());

print('$lib dependencies:');
for (final d in dependencies) {
print(d);
}
}
}
}
}
Loading

0 comments on commit 38c2f0a

Please sign in to comment.