Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# OverReact Changelog

## Unreleased
- Remove dependency on `transformer_utils`

## 5.5.0
- [#989] Optimize generated code to decrease dart2js compile size, saving ~577 bytes per component (when using `-03 --csp --minify`)
- [#992] Fix compilation errors for legacy boilerplate defined in libraries with a Dart language version of >=3.0
Expand Down
2 changes: 1 addition & 1 deletion lib/src/builder/codegen/accessors_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import 'package:analyzer/dart/ast/ast.dart';
import 'package:over_react/src/component_declaration/annotations.dart' as annotations;
import 'package:transformer_utils/transformer_utils.dart';
import 'package:over_react/src/builder/vendor/transformer_utils/transformer_utils.dart';

import '../parsing.dart';
import '../util.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/builder/codegen/component_factory_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import 'package:analyzer/dart/ast/ast.dart';
import 'package:over_react/src/component_declaration/annotations.dart' as annotations;
import 'package:transformer_utils/transformer_utils.dart';
import 'package:over_react/src/builder/vendor/transformer_utils/transformer_utils.dart';

import '../parsing.dart';
import '../util.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/builder/codegen/typed_map_impl_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

import 'package:analyzer/dart/ast/ast.dart';
import 'package:transformer_utils/transformer_utils.dart';
import 'package:over_react/src/builder/vendor/transformer_utils/transformer_utils.dart';

import '../parsing.dart';
import '../util.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/builder/parsing/ast_util.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:over_react/src/builder/codegen/names.dart';
import 'package:source_span/source_span.dart';
import 'package:transformer_utils/transformer_utils.dart';
import 'package:over_react/src/builder/vendor/transformer_utils/transformer_utils.dart';

import 'ast_util/classish.dart';
import 'util.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/builder/parsing/meta.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import 'dart:mirrors' as mirrors;
import 'package:analyzer/dart/ast/ast.dart';
import 'package:build/build.dart' show log;
import 'package:collection/collection.dart' show IterableExtension;
import 'package:transformer_utils/transformer_utils.dart';
import 'package:over_react/src/builder/vendor/transformer_utils/transformer_utils.dart';

import 'ast_util.dart';

Expand Down
251 changes: 251 additions & 0 deletions lib/src/builder/vendor/transformer_utils/src/analyzer_helpers.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
// Copyright 2015 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Copied from https://github.com/Workiva/dart_transformer_utils/tree/0.2.23/lib/

library;

import 'dart:mirrors' as mirrors;

import 'package:analyzer/dart/ast/ast.dart';
import 'package:collection/collection.dart' show IterableExtension;

/// Returns a copy of a class [member] declaration with [body] as a new
/// implementation.
///
/// Currently only supports:
/// * [FieldDeclaration] (single variable only)
/// * [MethodDeclaration] (getter, setter, and methods)
String copyClassMember(ClassMember? member, String body) {
if (member is FieldDeclaration) return _copyFieldDeclaration(member, body);
if (member is MethodDeclaration) {
if (member.isGetter) return _copyGetterDeclaration(member, body);
if (member.isSetter) return _copySetterDeclaration(member, body);
return _copyMethodDeclaration(member, body);
}
throw UnsupportedError('Unsupported class member type: ${member.runtimeType}. '
'Only FieldDeclaration and MethodDeclaration are supported.');
}

/// Finds and returns all declarations within a compilation [unit] that are
/// annotated with the given [annotation] class.
///
/// If this is being leveraged within a transformer, you can associate the
/// returned [DeclarationWithMeta] instance with the asset in which it is
/// located by passing in an [assetId].
Iterable<CompilationUnitMember> getDeclarationsAnnotatedBy(CompilationUnit unit, Type annotation) {
var annotationName = _getReflectedName(annotation);
return unit.declarations.where((member) {
return member.metadata.any((meta) => meta.name.name == annotationName);
});
}

/// Returns the value of the specified [expression] AST node if it represents a literal.
///
/// For non-literal nodes, the return value will be the result of calling [onUnsupportedExpression] with [expression].
///
/// If [onUnsupportedExpression] isn't specified, an [UnsupportedError] will be thrown.
///
/// Currently only supports:
/// * [StringLiteral]
/// * [BooleanLiteral]
/// * [IntegerLiteral]
/// * [NullLiteral]
dynamic getValue(Expression expression,
{dynamic Function(Expression expression)? onUnsupportedExpression}) {
if (expression is StringLiteral) {
var value = expression.stringValue;
if (value != null) {
return value;
}
} else if (expression is BooleanLiteral) {
return expression.value;
} else if (expression is IntegerLiteral) {
return expression.value;
} else if (expression is NullLiteral) {
return null;
}

if (onUnsupportedExpression != null) {
return onUnsupportedExpression(expression);
}

throw UnsupportedError('Unsupported expression: $expression. '
'Must be a uninterpolated string, boolean, integer, or null literal.');
}

/// Returns the first annotation AST node on [member] of type [annotationType],
/// or null if no matching annotations are found.
Annotation? getMatchingAnnotation(AnnotatedNode member, Type annotationType) {
// Be sure to use `originalDeclaration` so that generic parameters work.
final classMirror =
mirrors.reflectClass(annotationType).originalDeclaration as mirrors.ClassMirror;
String className = mirrors.MirrorSystem.getName(classMirror.simpleName);

// Find the annotation that matches [type]'s name.
return member.metadata.firstWhereOrNull((annotation) {
return _getClassName(annotation) == className;
});
}

/// Uses reflection to instantiate and returns the first annotation on [member] of type
/// [annotationType], or null if no matching annotations are found.
///
/// Annotation constructors are currently limited to the values supported by [getValue].
///
/// Naively assumes that the name of the [annotationType] class is canonical.
dynamic instantiateAnnotation(AnnotatedNode member, Type annotationType,
{dynamic Function(Expression argument)? onUnsupportedArgument}) {
final matchingAnnotation = getMatchingAnnotation(member, annotationType);

// If no annotation is found, return null.
if (matchingAnnotation == null) {
return null;
}

final matchingAnnotationArgs = matchingAnnotation.arguments;
if (matchingAnnotationArgs == null) {
throw Exception('Annotation not invocation of constructor: `$matchingAnnotation`. '
'This is likely due to invalid usage of the annotation class, but could'
'also be a name conflict with the specified type `$annotationType`');
}

// Get the parameters from the annotation's AST.
Map<Symbol, dynamic> namedParameters = {};
List positionalParameters = [];

matchingAnnotationArgs.arguments.forEach((argument) {
var onUnsupportedExpression =
onUnsupportedArgument == null ? null : (_) => onUnsupportedArgument(argument);

if (argument is NamedExpression) {
var name = argument.name.label.name;
var value = getValue(argument.expression, onUnsupportedExpression: onUnsupportedExpression);

namedParameters[Symbol(name)] = value;
} else {
var value = getValue(argument, onUnsupportedExpression: onUnsupportedExpression);

positionalParameters.add(value);
}
});

// Instantiate and return an instance of the annotation using reflection.
String constructorName = _getConstructorName(matchingAnnotation) ?? '';

// Be sure to use `originalDeclaration` so that generic parameters work.
final classMirror =
mirrors.reflectClass(annotationType).originalDeclaration as mirrors.ClassMirror;

try {
var instanceMirror =
classMirror.newInstance(Symbol(constructorName), positionalParameters, namedParameters);
return instanceMirror.reflectee;
} catch (e, stacktrace) {
throw Exception('Unable to instantiate annotation: $matchingAnnotation. This is '
'likely due to improper usage, or a naming conflict with '
'annotationType $annotationType. Original error: $e. Stacktrace: $stacktrace');
}
}

String _copyFieldDeclaration(FieldDeclaration decl, String initializer) {
var result = '';
if (decl.fields.type != null) {
result = '${decl.fields.type}';
} else if (decl.staticKeyword == null) {
result = 'var';
}
if (decl.staticKeyword != null) {
result = '${decl.staticKeyword} $result';
}
result = '$result ${decl.fields.variables.first.name.lexeme}';
if (initializer.isNotEmpty) {
result = '$result = $initializer;';
} else {
result = '$result;';
}
return result;
}

String _copyGetterDeclaration(MethodDeclaration decl, String body) {
var result = '';
if (decl.returnType != null) {
result = '${decl.returnType} get';
} else {
result = 'get';
}
if (decl.isStatic) {
result = 'static $result';
}

result = '$result ${decl.name.lexeme}';
if (decl.body.keyword != null) {
result = '$result ${decl.body.keyword}${decl.body.star ?? ''}';
}
result = '$result {\n$body\n}';
return result;
}

String _copySetterDeclaration(MethodDeclaration decl, String body) {
var result = 'void set';
if (decl.isStatic) {
result = 'static $result';
}
result = '$result ${decl.name.lexeme}${decl.parameters} {\n$body\n }';
return result;
}

String _copyMethodDeclaration(MethodDeclaration decl, String body) {
var result = '${decl.name.lexeme}';
if (decl.returnType != null) {
result = '${decl.returnType} $result';
}
if (decl.isStatic) {
result = 'static $result';
}
result = '$result${decl.parameters}';
if (decl.body.keyword != null) {
result = '$result ${decl.body.keyword}${decl.body.star ?? ''}';
}
result = '$result {\n$body\n }';
return result;
}

/// Returns the name of the class being instantiated for [annotation], or null
/// if the annotation is not the invocation of a constructor.
///
/// Workaround for a Dart analyzer issue where the constructor name is included
/// in [annotation.name].
String _getClassName(Annotation annotation) => annotation.name.name.split('.').first;

/// Returns the name of the constructor being instantiated for [annotation], or
/// null if the annotation is not the invocation of a named constructor.
///
/// Workaround for a Dart analyzer issue where the constructor name is included
/// in [annotation.name].
String? _getConstructorName(Annotation annotation) {
var constructorName = annotation.constructorName?.name;
if (constructorName == null) {
var periodIndex = annotation.name.name.indexOf('.');
if (periodIndex != -1) {
constructorName = annotation.name.name.substring(periodIndex + 1);
}
}

return constructorName;
}

/// Get the name of a [type] via reflection.
String _getReflectedName(Type type) =>
mirrors.MirrorSystem.getName(mirrors.reflectType(type).simpleName);
43 changes: 43 additions & 0 deletions lib/src/builder/vendor/transformer_utils/src/barback_utils.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// Copyright 2015 Workiva Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Copied from https://github.com/Workiva/dart_transformer_utils/tree/0.2.23/lib/

library;

import 'package:analyzer/dart/ast/ast.dart';
import 'package:build/build.dart';
import 'package:path/path.dart' as path;
import 'package:source_span/source_span.dart';

/// Converts [id] to a "package:" URI.
///
/// This will return a schemeless URI if [id] doesn't represent a library in
/// `lib/`.
Uri assetIdToPackageUri(AssetId id) {
if (!id.path.startsWith('lib/')) return Uri(path: id.path);
return Uri(scheme: 'package', path: path.url.join(id.package, id.path.replaceFirst('lib/', '')));
}

/// Returns a [SourceSpan] spanning from the beginning to the end of the given
/// [node]. The preceding comment and metadata will be excluded if
/// [skipCommentAndMetadata] is true.
SourceSpan getSpanForNode(SourceFile sourceFile, AstNode node,
{bool skipCommentAndMetadata = true}) {
if (skipCommentAndMetadata && node is AnnotatedNode) {
return sourceFile.span(node.firstTokenAfterCommentAndMetadata.offset, node.end);
}

return sourceFile.span(node.offset, node.end);
}
Loading