Added package code_buffer

This commit is contained in:
thomashii 2021-03-16 08:14:28 +08:00
parent 4cf7409c1d
commit 5b6f6bdf97
15 changed files with 646 additions and 8 deletions

View file

@ -1,8 +1,9 @@
# 3.0.1 (NNBD)
# 4.0.0 (NNBD)
* Changed Dart SDK requirements for all packages to ">=2.12.0 <3.0.0" to support NNBD.
* Updated pretty_logging to 2.0.0
* Updated angel_http_exception to 2.0.0
* Updated angel_cli to 3.0.0. (Rename not working)
* Updated pretty_logging to 3.0.0
* Updated angel_http_exception to 3.0.0
* Moved to https://github.com/dukefirehawk/cli
* Updated angel_route to 5.0.0
# 3.0.0 (Non NNBD)
* Changed Dart SDK requirements for all packages to ">=2.10.0 <3.0.0"

85
packages/code_buffer/.gitignore vendored Normal file
View file

@ -0,0 +1,85 @@
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
.packages
.pub/
build/
# If you're building an application, you may want to check-in your pubspec.lock
pubspec.lock
# Directory created by dartdoc
# If you don't generate documentation locally you can remove this line.
doc/api/
### Dart template
# See https://www.dartlang.org/tools/private-files.html
# Files and directories created by pub
# SDK 1.20 and later (no longer creates packages directories)
# Older SDK versions
# (Include if the minimum SDK version specified in pubsepc.yaml is earlier than 1.20)
.project
.buildlog
**/packages/
# Files created by dart2js
# (Most Dart developers will use pub build to compile Dart, use/modify these
# rules if you intend to use dart2js directly
# Convention is to use extension '.dart.js' for Dart compiled to Javascript to
# differentiate from explicit Javascript files)
*.dart.js
*.part.js
*.js.deps
*.js.map
*.info.json
# Directory created by dartdoc
# Don't commit pubspec lock file
# (Library packages only! Remove pattern if developing an application package)
### JetBrains template
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties

View file

@ -0,0 +1 @@
language: dart

View file

@ -0,0 +1,2 @@
# 1.0.1
* Added `CodeBuffer.noWhitespace()`.

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2017 Tobe O
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1,63 @@
# code_buffer
[![Pub](https://img.shields.io/pub/v/code_buffer.svg)](https://pub.dartlang.org/packages/code_buffer)
[![build status](https://travis-ci.org/thosakwe/code_buffer.svg)](https://travis-ci.org/thosakwe/code_buffer)
An advanced StringBuffer geared toward generating code, and source maps.
# Installation
In your `pubspec.yaml`:
```yaml
dependencies:
code_buffer: ^1.0.0
```
# Usage
Use a `CodeBuffer` just like any regular `StringBuffer`:
```dart
String someFunc() {
var buf = new CodeBuffer();
buf
..write('hello ')
..writeln('world!');
return buf.toString();
}
```
However, a `CodeBuffer` supports indentation.
```dart
void someOtherFunc() {
var buf = new CodeBuffer();
// Custom options...
var buf = new CodeBuffer(newline: '\r\n', space: '\t', trailingNewline: true);
// Any following lines will have an incremented indentation level...
buf.indent();
// And vice-versa:
buf.outdent();
}
```
`CodeBuffer` instances keep track of every `SourceSpan` they create.
This makes them useful for codegen tools, or to-JS compilers.
```dart
void someFunc(CodeBuffer buf) {
buf.write('hello');
expect(buf.lastLine.text, 'hello');
buf.writeln('world');
expect(buf.lastLine.lastSpan.start.column, 5);
}
```
You can copy a `CodeBuffer` into another, heeding indentation rules:
```dart
void yetAnotherFunc(CodeBuffer a, CodeBuffer b) {
b.copyInto(a);
}
```

View file

@ -0,0 +1,3 @@
analyzer:
strong-mode:
implicit-casts: false

View file

@ -0,0 +1,45 @@
import 'package:code_buffer/code_buffer.dart';
import 'package:test/test.dart';
/// Use a `CodeBuffer` just like any regular `StringBuffer`:
String someFunc() {
var buf = new CodeBuffer();
buf
..write('hello ')
..writeln('world!');
return buf.toString();
}
/// However, a `CodeBuffer` supports indentation.
void someOtherFunc() {
var buf = new CodeBuffer();
// Custom options...
// ignore: unused_local_variable
var customBuf = new CodeBuffer(newline: '\r\n', space: '\t', trailingNewline: true);
// Without whitespace..
// ignore: unused_local_variable
var minifyingBuf = new CodeBuffer.noWhitespace();
// Any following lines will have an incremented indentation level...
buf.indent();
// And vice-versa:
buf.outdent();
}
/// `CodeBuffer` instances keep track of every `SourceSpan` they create.
//This makes them useful for codegen tools, or to-JS compilers.
void yetAnotherOtherFunc(CodeBuffer buf) {
buf.write('hello');
expect(buf.lastLine!.text, 'hello');
buf.writeln('world');
expect(buf.lastLine!.lastSpan!.start.column, 5);
}
/// You can copy a `CodeBuffer` into another, heeding indentation rules:
void yetEvenAnotherFunc(CodeBuffer a, CodeBuffer b) {
b.copyInto(a);
}

View file

@ -0,0 +1,229 @@
import 'package:source_span/source_span.dart';
/// An advanced StringBuffer geared toward generating code, and source maps.
class CodeBuffer implements StringBuffer {
/// The character sequence used to represent a line break.
final String newline;
/// The character sequence used to represent a space/tab.
final String space;
/// The source URL to be applied to all generated [SourceSpan] instances.
final sourceUrl;
/// If `true` (default: `false`), then an additional [newline] will be inserted at the end of the generated string.
final bool trailingNewline;
final List<CodeBufferLine> _lines = [];
CodeBufferLine? _currentLine, _lastLine;
int _indentationLevel = 0;
int _length = 0;
CodeBuffer(
{this.space: ' ',
this.newline: '\n',
this.trailingNewline: false,
this.sourceUrl});
/// Creates a [CodeBuffer] that does not emit additional whitespace.
factory CodeBuffer.noWhitespace({sourceUrl}) => CodeBuffer(
space: '', newline: '', trailingNewline: false, sourceUrl: sourceUrl);
/// The last line created within this buffer.
CodeBufferLine? get lastLine => _lastLine;
/// Returns an immutable collection of the [CodeBufferLine]s within this instance.
List<CodeBufferLine> get lines => List<CodeBufferLine>.unmodifiable(_lines);
@override
bool get isEmpty => _lines.isEmpty;
@override
bool get isNotEmpty => _lines.isNotEmpty;
@override
int get length => _length;
CodeBufferLine _createLine() {
var start = SourceLocation(
_length,
sourceUrl: sourceUrl,
line: _lines.length,
column: _indentationLevel * space.length,
);
var line = CodeBufferLine._(_indentationLevel, start).._end = start;
_lines.add(_lastLine = line);
return line;
}
/// Increments the indentation level.
void indent() {
_indentationLevel++;
}
/// Decrements the indentation level, if it is greater than `0`.
void outdent() {
if (_indentationLevel > 0) _indentationLevel--;
}
/// Copies the contents of this [CodeBuffer] into another, preserving indentation and source mapping information.
void copyInto(CodeBuffer other) {
if (_lines.isEmpty) return;
int i = 0;
for (var line in _lines) {
// To compute offset:
// 1. Find current length of other
// 2. Add length of its newline
// 3. Add indentation
var column = (other._indentationLevel + line.indentationLevel) *
other.space.length;
var offset = other._length + other.newline.length + column;
// Re-compute start + end
var start = SourceLocation(
offset,
sourceUrl: other.sourceUrl,
line: other._lines.length + i,
column: column,
);
var end = SourceLocation(
offset + line.span.length,
sourceUrl: other.sourceUrl,
line: start.line,
column: column + line._buf.length,
);
var clone = CodeBufferLine._(
line.indentationLevel + other._indentationLevel, start)
.._end = end
.._buf.write(line._buf.toString());
// Adjust lastSpan
if (line._lastSpan != null) {
var s = line._lastSpan!.start;
var lastSpanColumn =
((line.indentationLevel + other._indentationLevel) *
other.space.length) +
line.text.indexOf(line._lastSpan!.text);
clone._lastSpan = SourceSpan(
SourceLocation(
offset + s.offset,
sourceUrl: other.sourceUrl,
line: clone.span.start.line,
column: lastSpanColumn,
),
SourceLocation(
offset + s.offset + line._lastSpan!.length,
sourceUrl: other.sourceUrl,
line: clone.span.end.line,
column: lastSpanColumn + line._lastSpan!.length,
),
line._lastSpan!.text,
);
}
other._lines.add(other._currentLine = other._lastLine = clone);
// Adjust length accordingly...
other._length = offset + clone.span.length;
i++;
}
other.writeln();
}
@override
void clear() {
_lines.clear();
_length = _indentationLevel = 0;
_currentLine = null;
}
@override
void writeCharCode(int charCode) {
_currentLine ??= _createLine();
_currentLine!._buf.writeCharCode(charCode);
var end = _currentLine!._end;
_currentLine!._end = SourceLocation(
end.offset + 1,
sourceUrl: end.sourceUrl,
line: end.line,
column: end.column + 1,
);
_length++;
_currentLine!._lastSpan =
SourceSpan(end, _currentLine!._end, String.fromCharCode(charCode));
}
@override
void write(Object? obj) {
var msg = obj.toString();
_currentLine ??= _createLine();
_currentLine!._buf.write(msg);
var end = _currentLine!._end;
_currentLine!._end = SourceLocation(
end.offset + msg.length,
sourceUrl: end.sourceUrl,
line: end.line,
column: end.column + msg.length,
);
_length += msg.length;
_currentLine!._lastSpan = SourceSpan(end, _currentLine!._end, msg);
}
@override
void writeln([Object? obj = ""]) {
if (obj != null && obj != '') write(obj);
_currentLine = null;
_length++;
}
@override
void writeAll(Iterable objects, [String separator = ""]) {
write(objects.join(separator));
}
@override
String toString() {
var buf = StringBuffer();
int i = 0;
for (var line in lines) {
if (i++ > 0) buf.write(newline);
for (int j = 0; j < line.indentationLevel; j++) buf.write(space);
buf.write(line._buf.toString());
}
if (trailingNewline == true) buf.write(newline);
return buf.toString();
}
}
/// Represents a line of text within a [CodeBuffer].
class CodeBufferLine {
/// Mappings from one [SourceSpan] to another, to aid with generating dynamic source maps.
final Map<SourceSpan, SourceSpan> sourceMappings = {};
/// The level of indentation preceding this line.
final int indentationLevel;
final SourceLocation _start;
final StringBuffer _buf = StringBuffer();
late SourceLocation _end;
SourceSpan? _lastSpan;
CodeBufferLine._(this.indentationLevel, this._start);
/// The [SourceSpan] corresponding to the last text written to this line.
SourceSpan? get lastSpan => _lastSpan;
/// The [SourceSpan] corresponding to this entire line.
SourceSpan get span => SourceSpan(_start, _end, _buf.toString());
/// The text within this line.
String get text => _buf.toString();
}

View file

@ -0,0 +1,12 @@
name: code_buffer
version: 2.0.0
description: An advanced StringBuffer geared toward generating code, and source maps.
author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/thosakwe/code_buffer
environment:
sdk: '>=2.12.0 <3.0.0'
dependencies:
charcode: ^1.2.0
source_span: ^1.8.1
dev_dependencies:
test: ^1.16.8

View file

@ -0,0 +1,45 @@
import 'package:code_buffer/code_buffer.dart';
import 'package:test/test.dart';
main() {
var a = new CodeBuffer(), b = new CodeBuffer();
setUp(() {
a.writeln('outer block 1');
b..writeln('inner block 1')..writeln('inner block 2');
b.copyInto(a..indent());
a
..outdent()
..writeln('outer block 2');
});
tearDown(() {
a.clear();
b.clear();
});
test('sets correct text', () {
expect(
a.toString(),
[
'outer block 1',
' inner block 1',
' inner block 2',
'outer block 2',
].join('\n'));
});
test('sets lastLine+lastSpan', () {
var c = new CodeBuffer()
..indent()
..write('>')
..writeln('innermost');
c.copyInto(a);
expect(a.lastLine!.text, '>innermost');
expect(a.lastLine!.span.start.column, 2);
expect(a.lastLine!.lastSpan!.start.line, 4);
expect(a.lastLine!.lastSpan!.start.column, 3);
expect(a.lastLine!.lastSpan!.end.line, 4);
expect(a.lastLine!.lastSpan!.end.column, 12);
});
}

View file

@ -0,0 +1,44 @@
import 'package:charcode/charcode.dart';
import 'package:code_buffer/code_buffer.dart';
import 'package:test/test.dart';
main() {
var buf = new CodeBuffer();
tearDown(buf.clear);
test('writeCharCode', () {
buf.writeCharCode($x);
expect(buf.lastLine!.lastSpan!.start.column, 0);
expect(buf.lastLine!.lastSpan!.start.line, 0);
expect(buf.lastLine!.lastSpan!.end.column, 1);
expect(buf.lastLine!.lastSpan!.end.line, 0);
});
test('write', () {
buf.write('foo');
expect(buf.lastLine!.lastSpan!.start.column, 0);
expect(buf.lastLine!.lastSpan!.start.line, 0);
expect(buf.lastLine!.lastSpan!.end.column, 3);
expect(buf.lastLine!.lastSpan!.end.line, 0);
});
test('multiple writes in one line', () {
buf..write('foo')..write('baz');
expect(buf.lastLine!.lastSpan!.start.column, 3);
expect(buf.lastLine!.lastSpan!.start.line, 0);
expect(buf.lastLine!.lastSpan!.end.column, 6);
expect(buf.lastLine!.lastSpan!.end.line, 0);
});
test('multiple lines', () {
buf
..writeln('foo')
..write('bar')
..write('+')
..writeln('baz');
expect(buf.lastLine!.lastSpan!.start.column, 4);
expect(buf.lastLine!.lastSpan!.start.line, 1);
expect(buf.lastLine!.lastSpan!.end.column, 7);
expect(buf.lastLine!.lastSpan!.end.line, 1);
});
}

View file

@ -0,0 +1,87 @@
import 'package:charcode/charcode.dart';
import 'package:code_buffer/code_buffer.dart';
import 'package:test/test.dart';
main() {
var buf = new CodeBuffer();
tearDown(buf.clear);
test('writeCharCode', () {
buf.writeCharCode($x);
expect(buf.toString(), 'x');
});
test('write', () {
buf.write('hello world');
expect(buf.toString(), 'hello world');
});
test('custom space', () {
var b = new CodeBuffer(space: '+')
..writeln('foo')
..indent()
..writeln('baz');
expect(b.toString(), 'foo\n+baz');
});
test('custom newline', () {
var b = new CodeBuffer(newline: 'N')
..writeln('foo')
..indent()
..writeln('baz');
expect(b.toString(), 'fooN baz');
});
test('trailing newline', () {
var b = new CodeBuffer(trailingNewline: true)..writeln('foo');
expect(b.toString(), 'foo\n');
});
group('multiple lines', () {
setUp(() {
buf..writeln('foo')..writeln('bar')..writeln('baz');
expect(buf.lines, hasLength(3));
expect(buf.lines[0].text, 'foo');
expect(buf.lines[1].text, 'bar');
expect(buf.lines[2].text, 'baz');
});
});
test('indent', () {
buf
..writeln('foo')
..indent()
..writeln('bar')
..indent()
..writeln('baz')
..outdent()
..writeln('quux')
..outdent()
..writeln('end');
expect(buf.toString(), 'foo\n bar\n baz\n quux\nend');
});
group('sets lastLine text', () {
test('writeCharCode', () {
buf.writeCharCode($x);
expect(buf.lastLine!.text, 'x');
});
test('write', () {
buf.write('hello world');
expect(buf.lastLine!.text, 'hello world');
});
});
group('sets lastLine lastSpan', () {
test('writeCharCode', () {
buf.writeCharCode($x);
expect(buf.lastLine!.lastSpan!.text, 'x');
});
test('write', () {
buf.write('hello world');
expect(buf.lastLine!.lastSpan!.text, 'hello world');
});
});
}

View file

@ -1,5 +1,5 @@
name: angel_http_exception
version: 2.1.0
version: 3.0.0
description: Exception class that can be serialized to JSON and serialized to clients.
#author: Tobe O <thosakwe@gmail.com>
homepage: https://github.com/dukefirehawk/angel/packages/http_exception

View file

@ -1,8 +1,8 @@
name: pretty_logging
version: 2.1.0
version: 4.0.0
description: Standalone helper for colorful logging output, using pkg:io AnsiCode.
author: Tobe Osakwe <thosakwe@gmail.com>
homepage: https://github.com/angel-dart/pretty_logging
#author: Tobe Osakwe <thosakwe@gmail.com>
homepage: https://github.com/dukefirehawk/angel
environment:
sdk: '>=2.12.0 <3.0.0'
dependencies: