Skip to content

Commit

Permalink
Merge pull request #61 from nyxx-discord/dev
Browse files Browse the repository at this point in the history
Release 4.2.0
  • Loading branch information
abitofevrything authored May 18, 2022
2 parents 919c9fc + 73b6015 commit e9b333c
Show file tree
Hide file tree
Showing 37 changed files with 3,389 additions and 524 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/deploy_docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
run: dart pub get

- name: Generate docs
run: dartdoc
run: dart doc

- name: Extract branch name
shell: bash
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/unit_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,11 @@ jobs:
- name: Unit tests
run: dart run test --coverage="coverage" test/unit/**

- name: Integration tests
run: dart run test --coverage="coverage" test/integration/**

- name: Format coverage
run: dart run coverage:format_coverage --lcov --in=coverage --out=coverage/coverage.lcov --packages=.packages --report-on=lib
run: dart run coverage:format_coverage --lcov --in=coverage --out=coverage/coverage.lcov --packages=.dart_tool/package_config.json --report-on=lib

- name: Generate coverage
run: genhtml coverage/coverage.lcov -o coverage/coverage_gen
Expand Down
8 changes: 5 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
# Files and directories created by pub.
.dart_tool/
.packages
pubspec.lock

# Conventional directory for build output.
build/

# Generated files
*.g.dart
*.exe

# Local
doc/
.vscode/

pubspec.lock

.idea/
27 changes: 26 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,35 @@
## 4.2.0
__New features__:
- Added a script which allows `nyxx_commands` to be compiled. For more information, run `dart pub global activate nyxx_commands` and `nyxx-compile --help`.
- Implemented support for permissions V2. See `PermissionsCheck` for more.

__Deprecaations__:
- Deprecated `AbstractCheck.permissions` and all associated features.

## 4.2.0-dev.1
__New features__:
- Added a script which allows `nyxx_commands` to be compiled. For more information, run `dart pub global activate nyxx_commands` and `nyxx-compile --help`.

## 4.2.0-dev.0
__Deprecations__:
- Deprecated `AbstractCheck.permissions` and all associated features.

__New features__:
- Added `AbtractCheck.allowsDm` and `AbstractCheck.requiredPermissions` for integrating checks with permissions v2.
- Updated `Check.deny`, `Check.any` and `Check.all` to work with permissions v2.
- Added `PermissionsCheck`, for checking if users have a specific permission.

__Miscellaneous__:
- Bump `nyxx_interactions` to 4.2.0.
- Added proper names to context type checks if none is provided.

## 4.1.2
__Bug fixes__:
- Fixes an issue where slash commands nested within text-only commands would not be registered

## 4.1.1
__Bug fixes__:
- Correctly export the `@AUtocomplete(...)` annotation.
- Correctly export the `@Autocomplete(...)` annotation.

## 4.1.0
__New features__:
Expand Down
2 changes: 1 addition & 1 deletion analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ linter:
implementation_imports: false

analyzer:
exclude: [build/**]
exclude: [build/**, "*.g.dart"]
language:
strict-raw-types: true
strong-mode:
Expand Down
121 changes: 121 additions & 0 deletions bin/compile.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
// Copyright 2021 Abitofevrything and others.
//
// 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.

import 'dart:convert';
import 'dart:io';

import 'package:args/args.dart';
import 'package:logging/logging.dart';

import 'compile/generator.dart';

void main(List<String> args) async {
late ArgParser parser;
parser = ArgParser()
..addFlag(
'help',
abbr: 'h',
negatable: false,
help: 'Print this help and exit',
)
..addOption(
'output',
abbr: 'o',
defaultsTo: 'out.g.dart',
help: 'The file where generated output should be written to',
)
..addOption(
'verbosity',
abbr: 'v',
defaultsTo: 'info',
allowed: Level.LEVELS.map((e) => e.name.toLowerCase()),
help: 'Change the verbosity level of the command-line output',
)
..addFlag(
'compile',
abbr: 'c',
defaultsTo: true,
help: 'Compile the generated file with `dart compile exe`',
)
..addFlag(
'format',
abbr: 'f',
defaultsTo: true,
help: 'Format the generated output before compiling',
)
..addFlag(
'complete',
defaultsTo: false,
help: 'Generate metadata for all the files in your program, instead of just the necessary'
' ones. This can help in cases where your program does not run when using the normal'
' compiler.',
);

if (args.isEmpty) {
printHelp(parser);
return;
}

ArgResults result = parser.parse(args);

// Help

if (result['help'] as bool) {
printHelp(parser);
return;
}

// Logging

Logger.root.level = Level.LEVELS.firstWhere(
(element) => element.name.toLowerCase() == result['verbosity'],
);
Logger.root.onRecord.listen((LogRecord rec) {
print("[${rec.time}] [${rec.level.name}] ${rec.message}");
});

// Generation

await generate(
result.rest.first,
result['output'] as String,
result['format'] as bool,
result['complete'] as bool,
);

// Compilation

if (result['compile'] as bool) {
logger.info('Compiling file to executable');

Process compiler = await Process.start('dart', ['compile', 'exe', result['output'] as String]);

compiler.stdout.transform(utf8.decoder).listen(stdout.write);
compiler.stderr.transform(utf8.decoder).listen(stderr.write);
}
}

void printHelp(ArgParser p) {
print(
'''
Generate code from a Dart program that contains metadata about types and function metadata, and can
be compiled to run a program written with nyxx_commands.
Usage: nyxx-compile [options] <file>
Options:
''',
);
print(p.usage);
}
134 changes: 134 additions & 0 deletions bin/compile/element_tree_visitor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
// Copyright 2021 Abitofevrything and others.
//
// 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.

import 'dart:async';

import 'package:analyzer/dart/analysis/analysis_context.dart';
import 'package:analyzer/dart/analysis/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:nyxx_commands/src/errors.dart';

import 'generator.dart';

/// An AST visitor that checks every file in the entire program, following imports, exports and part
/// directives. Files that are deemed "interesting" are visited in full by this visitor.
///
/// Files are deemed "interesting" if:
/// - The file is part of `package:nyxx_commands`
/// - The file imports an "interesting" file
class EntireAstVisitor extends RecursiveAstVisitor<void> {
static final Map<String, SomeResolvedUnitResult> _cache = {};
final List<String> _interestingSources = [];

final AnalysisContext context;
final bool slow;

EntireAstVisitor(this.context, this.slow);

/// Makes this visitor check all the imported, exported or "part-ed" files in [element], visiting
/// ones that are deemed "interesting".
Future<void> visitLibrary(LibraryElement element) async {
List<String> visited = [];

void recursivelyGatherSources(LibraryElement element) {
String source = element.source.fullName;

logger.finest('Checking source "$source"');

if (visited.contains(source)) {
return;
}

visited.add(source);

if (isLibraryInteresting(element)) {
_interestingSources.add(source);
}

for (final library in [...element.importedLibraries, ...element.exportedLibraries]) {
recursivelyGatherSources(library);
}
}

recursivelyGatherSources(element);

while (_interestingSources.isNotEmpty) {
List<String> interestingSources = _interestingSources.sublist(0);
_interestingSources.clear();

logger.fine('Visiting interesting sources $interestingSources');

await Future.wait(interestingSources.map(visitUnit));
}
}

final List<LibraryElement> _checkingLibraries = [];
static final Map<LibraryElement, bool> _interestingCache = {};

/// Returns whether a given library is "interesting"
bool isLibraryInteresting(LibraryElement element) {
if (slow) {
return true;
}

if (_interestingCache.containsKey(element)) {
return _interestingCache[element]!;
}

if (_checkingLibraries.contains(element)) {
return false;
}

bool ret;

_checkingLibraries.add(element);

if (element.identifier.startsWith('package:nyxx_commands')) {
ret = true;
} else {
ret = element.importedLibraries.any((library) => isLibraryInteresting(library)) ||
element.exportedLibraries.any((library) => isLibraryInteresting(library));
}

_checkingLibraries.removeLast();

return _interestingCache[element] = ret;
}

/// Makes this visitor get the full AST for a given source and visit it.
Future<void> visitUnit(String source) async {
logger.finer('Getting AST for source "$source"');

SomeResolvedUnitResult result =
_cache[source] ??= await context.currentSession.getResolvedUnit(source);

if (result is! ResolvedUnitResult) {
throw CommandsError('Got invalid analysis result for source $source');
}

logger.finer('Got AST for source "$source"');

result.unit.accept(this);
}

@override
void visitPartDirective(PartDirective directive) {
super.visitPartDirective(directive);

// Visit "part-ed" files of interesting sources
_interestingSources.add(directive.uriSource!.fullName);
}
}
Loading

0 comments on commit e9b333c

Please sign in to comment.